summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorandroid-build-team Robot <android-build-team-robot@google.com>2017-07-16 07:34:51 +0000
committerandroid-build-team Robot <android-build-team-robot@google.com>2017-07-16 07:34:51 +0000
commit27328a4f25f3c0bd82910c079a9c2810c33814f0 (patch)
tree4c371e93cf162adffcb891752bdeb3f902252d18
parent0842d9b2df955c212cddbb0f9784b6a5e3d6ec40 (diff)
parentd635ac295850ba23d528c02b1e5c6eb44b64b22b (diff)
downloadandroid_packages_providers_DownloadProvider-27328a4f25f3c0bd82910c079a9c2810c33814f0.tar.gz
android_packages_providers_DownloadProvider-27328a4f25f3c0bd82910c079a9c2810c33814f0.tar.bz2
android_packages_providers_DownloadProvider-27328a4f25f3c0bd82910c079a9c2810c33814f0.zip
release-request-05263112-375a-4b1f-a657-a14bb2a5c5a3-for-git_oc-mr1-release-4185249 snap-temp-L63000000082739046
Change-Id: I4f34c85a88bbca8e943f99763cf26beacc5bf847
-rw-r--r--src/com/android/providers/downloads/DownloadInfo.java7
-rw-r--r--src/com/android/providers/downloads/DownloadNotifier.java6
-rw-r--r--src/com/android/providers/downloads/DownloadProvider.java11
-rw-r--r--src/com/android/providers/downloads/DownloadThread.java51
-rw-r--r--src/com/android/providers/downloads/Helpers.java8
-rw-r--r--src/com/android/providers/downloads/RealSystemFacade.java7
-rw-r--r--src/com/android/providers/downloads/StorageUtils.java170
-rw-r--r--src/com/android/providers/downloads/SystemFacade.java3
-rw-r--r--tests/AndroidManifest.xml2
-rw-r--r--tests/src/com/android/providers/downloads/AbstractDownloadProviderFunctionalTest.java35
-rw-r--r--tests/src/com/android/providers/downloads/FakeSystemFacade.java9
-rw-r--r--tests/src/com/android/providers/downloads/StorageTest.java249
12 files changed, 51 insertions, 507 deletions
diff --git a/src/com/android/providers/downloads/DownloadInfo.java b/src/com/android/providers/downloads/DownloadInfo.java
index c571de4d..9ad7e755 100644
--- a/src/com/android/providers/downloads/DownloadInfo.java
+++ b/src/com/android/providers/downloads/DownloadInfo.java
@@ -380,13 +380,6 @@ public class DownloadInfo {
}
}
- public boolean isOnCache() {
- return (mDestination == Downloads.Impl.DESTINATION_CACHE_PARTITION
- || mDestination == Downloads.Impl.DESTINATION_SYSTEMCACHE_PARTITION
- || mDestination == Downloads.Impl.DESTINATION_CACHE_PARTITION_NOROAMING
- || mDestination == Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE);
- }
-
public Uri getMyDownloadsUri() {
return ContentUris.withAppendedId(Downloads.Impl.CONTENT_URI, mId);
}
diff --git a/src/com/android/providers/downloads/DownloadNotifier.java b/src/com/android/providers/downloads/DownloadNotifier.java
index c36dbd8c..71807640 100644
--- a/src/com/android/providers/downloads/DownloadNotifier.java
+++ b/src/com/android/providers/downloads/DownloadNotifier.java
@@ -264,11 +264,7 @@ public class DownloadNotifier {
if (Downloads.Impl.isStatusError(status)) {
action = Constants.ACTION_LIST;
} else {
- if (destination != Downloads.Impl.DESTINATION_SYSTEMCACHE_PARTITION) {
- action = Constants.ACTION_OPEN;
- } else {
- action = Constants.ACTION_LIST;
- }
+ action = Constants.ACTION_OPEN;
}
final Intent intent = new Intent(action, uri, mContext, DownloadReceiver.class);
diff --git a/src/com/android/providers/downloads/DownloadProvider.java b/src/com/android/providers/downloads/DownloadProvider.java
index d50b394c..d47010dd 100644
--- a/src/com/android/providers/downloads/DownloadProvider.java
+++ b/src/com/android/providers/downloads/DownloadProvider.java
@@ -580,8 +580,7 @@ public final class DownloadProvider extends ContentProvider {
if (getContext().checkCallingOrSelfPermission(Downloads.Impl.PERMISSION_ACCESS_ADVANCED)
!= PackageManager.PERMISSION_GRANTED
&& (dest == Downloads.Impl.DESTINATION_CACHE_PARTITION
- || dest == Downloads.Impl.DESTINATION_CACHE_PARTITION_NOROAMING
- || dest == Downloads.Impl.DESTINATION_SYSTEMCACHE_PARTITION)) {
+ || dest == Downloads.Impl.DESTINATION_CACHE_PARTITION_NOROAMING)) {
throw new SecurityException("setting destination to : " + dest +
" not allowed, unless PERMISSION_ACCESS_ADVANCED is granted");
}
@@ -608,12 +607,6 @@ public final class DownloadProvider extends ContentProvider {
getCallingPackage()) != AppOpsManager.MODE_ALLOWED) {
throw new SecurityException("No permission to write");
}
-
- } else if (dest == Downloads.Impl.DESTINATION_SYSTEMCACHE_PARTITION) {
- getContext().enforcePermission(
- android.Manifest.permission.ACCESS_CACHE_FILESYSTEM,
- Binder.getCallingPid(), Binder.getCallingUid(),
- "need ACCESS_CACHE_FILESYSTEM permission to use system cache");
}
filteredValues.put(Downloads.Impl.COLUMN_DESTINATION, dest);
}
@@ -1306,6 +1299,8 @@ public final class DownloadProvider extends ContentProvider {
try {
getContext().getContentResolver().delete(Uri.parse(mediaUri), null,
null);
+ } catch (Exception e) {
+ Log.w(Constants.TAG, "Failed to delete media entry: " + e);
} finally {
Binder.restoreCallingIdentity(token);
}
diff --git a/src/com/android/providers/downloads/DownloadThread.java b/src/com/android/providers/downloads/DownloadThread.java
index e101c74d..9c920053 100644
--- a/src/com/android/providers/downloads/DownloadThread.java
+++ b/src/com/android/providers/downloads/DownloadThread.java
@@ -25,6 +25,7 @@ import static android.provider.Downloads.Impl.STATUS_CANCELED;
import static android.provider.Downloads.Impl.STATUS_CANNOT_RESUME;
import static android.provider.Downloads.Impl.STATUS_FILE_ERROR;
import static android.provider.Downloads.Impl.STATUS_HTTP_DATA_ERROR;
+import static android.provider.Downloads.Impl.STATUS_INSUFFICIENT_SPACE_ERROR;
import static android.provider.Downloads.Impl.STATUS_PAUSED_BY_APP;
import static android.provider.Downloads.Impl.STATUS_QUEUED_FOR_WIFI;
import static android.provider.Downloads.Impl.STATUS_RUNNING;
@@ -47,7 +48,6 @@ import static java.net.HttpURLConnection.HTTP_PRECON_FAILED;
import static java.net.HttpURLConnection.HTTP_SEE_OTHER;
import static java.net.HttpURLConnection.HTTP_UNAVAILABLE;
-import android.app.job.JobInfo;
import android.app.job.JobParameters;
import android.content.ContentValues;
import android.content.Context;
@@ -64,6 +64,7 @@ import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.SystemClock;
+import android.os.storage.StorageManager;
import android.provider.Downloads;
import android.system.ErrnoException;
import android.system.Os;
@@ -117,6 +118,7 @@ public class DownloadThread extends Thread {
private final SystemFacade mSystemFacade;
private final DownloadNotifier mNotifier;
private final NetworkPolicyManager mNetworkPolicy;
+ private final StorageManager mStorage;
private final DownloadJobService mJobService;
private final JobParameters mParams;
@@ -245,6 +247,7 @@ public class DownloadThread extends Thread {
mSystemFacade = Helpers.getSystemFacade(mContext);
mNotifier = Helpers.getDownloadNotifier(mContext);
mNetworkPolicy = mContext.getSystemService(NetworkPolicyManager.class);
+ mStorage = mContext.getSystemService(StorageManager.class);
mJobService = service;
mParams = params;
@@ -564,35 +567,23 @@ public class DownloadThread extends Thread {
out = new ParcelFileDescriptor.AutoCloseOutputStream(outPfd);
}
- // Pre-flight disk space requirements, when known
- if (mInfoDelta.mTotalBytes > 0) {
- final long curSize = Os.fstat(outFd).st_size;
- final long newBytes = mInfoDelta.mTotalBytes - curSize;
-
- StorageUtils.ensureAvailableSpace(mContext, outFd, newBytes);
-
- try {
- // We found enough space, so claim it for ourselves
- Os.posix_fallocate(outFd, 0, mInfoDelta.mTotalBytes);
- } catch (ErrnoException e) {
- if (e.errno == OsConstants.ENOSYS || e.errno == OsConstants.ENOTSUP) {
- Log.w(TAG, "fallocate() not supported; falling back to ftruncate()");
- Os.ftruncate(outFd, mInfoDelta.mTotalBytes);
- } else {
- throw e;
- }
- }
- }
-
// Move into place to begin writing
Os.lseek(outFd, mInfoDelta.mCurrentBytes, OsConstants.SEEK_SET);
-
} catch (ErrnoException e) {
throw new StopRequestException(STATUS_FILE_ERROR, e);
} catch (IOException e) {
throw new StopRequestException(STATUS_FILE_ERROR, e);
}
+ try {
+ // Pre-flight disk space requirements, when known
+ if (mInfoDelta.mTotalBytes > 0 && mStorage.isAllocationSupported(outFd)) {
+ mStorage.allocateBytes(outFd, mInfoDelta.mTotalBytes);
+ }
+ } catch (IOException e) {
+ throw new StopRequestException(STATUS_INSUFFICIENT_SPACE_ERROR, e);
+ }
+
// Start streaming data, periodically watch for pause/cancel
// commands and checking disk space as needed.
transferData(in, out, outFd);
@@ -650,14 +641,6 @@ public class DownloadThread extends Thread {
}
try {
- // When streaming, ensure space before each write
- if (mInfoDelta.mTotalBytes == -1) {
- final long curSize = Os.fstat(outFd).st_size;
- final long newBytes = (mInfoDelta.mCurrentBytes + len) - curSize;
-
- StorageUtils.ensureAvailableSpace(mContext, outFd, newBytes);
- }
-
out.write(buffer, 0, len);
mMadeProgress = true;
@@ -665,8 +648,6 @@ public class DownloadThread extends Thread {
updateProgress(outFd);
- } catch (ErrnoException e) {
- throw new StopRequestException(STATUS_FILE_ERROR, e);
} catch (IOException e) {
throw new StopRequestException(STATUS_FILE_ERROR, e);
}
@@ -674,7 +655,8 @@ public class DownloadThread extends Thread {
// Finished without error; verify length if known
if (mInfoDelta.mTotalBytes != -1 && mInfoDelta.mCurrentBytes != mInfoDelta.mTotalBytes) {
- throw new StopRequestException(STATUS_HTTP_DATA_ERROR, "Content length mismatch");
+ throw new StopRequestException(STATUS_HTTP_DATA_ERROR, "Content length mismatch; found "
+ + mInfoDelta.mCurrentBytes + " instead of " + mInfoDelta.mTotalBytes);
}
}
@@ -743,7 +725,8 @@ public class DownloadThread extends Thread {
if (info.isRoaming() && !mInfo.isRoamingAllowed()) {
throw new StopRequestException(STATUS_WAITING_FOR_NETWORK, "Network is roaming");
}
- if (info.isMetered() && !mInfo.isMeteredAllowed(mInfoDelta.mTotalBytes)) {
+ if (mSystemFacade.isNetworkMetered(mNetwork)
+ && !mInfo.isMeteredAllowed(mInfoDelta.mTotalBytes)) {
throw new StopRequestException(STATUS_WAITING_FOR_NETWORK, "Network is metered");
}
}
diff --git a/src/com/android/providers/downloads/Helpers.java b/src/com/android/providers/downloads/Helpers.java
index 7354076b..2b55eb87 100644
--- a/src/com/android/providers/downloads/Helpers.java
+++ b/src/com/android/providers/downloads/Helpers.java
@@ -556,14 +556,6 @@ public class Helpers {
return context.getCacheDir();
}
- case Downloads.Impl.DESTINATION_SYSTEMCACHE_PARTITION:
- if (running) {
- return new File(Environment.getDownloadCacheDirectory(),
- Constants.DIRECTORY_CACHE_RUNNING);
- } else {
- return Environment.getDownloadCacheDirectory();
- }
-
case Downloads.Impl.DESTINATION_EXTERNAL:
final File target = new File(
Environment.getExternalStorageDirectory(), Environment.DIRECTORY_DOWNLOADS);
diff --git a/src/com/android/providers/downloads/RealSystemFacade.java b/src/com/android/providers/downloads/RealSystemFacade.java
index df1d245f..1c2ba581 100644
--- a/src/com/android/providers/downloads/RealSystemFacade.java
+++ b/src/com/android/providers/downloads/RealSystemFacade.java
@@ -25,6 +25,7 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.ConnectivityManager;
import android.net.Network;
+import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.security.NetworkSecurityPolicy;
import android.security.net.config.ApplicationConfig;
@@ -61,6 +62,12 @@ class RealSystemFacade implements SystemFacade {
}
@Override
+ public boolean isNetworkMetered(Network network) {
+ return !mContext.getSystemService(ConnectivityManager.class).getNetworkCapabilities(network)
+ .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
+ }
+
+ @Override
public long getMaxBytesOverMobile() {
final Long value = DownloadManager.getMaxBytesOverMobile(mContext);
return (value == null) ? Long.MAX_VALUE : value;
diff --git a/src/com/android/providers/downloads/StorageUtils.java b/src/com/android/providers/downloads/StorageUtils.java
index d7a5c33b..4d332816 100644
--- a/src/com/android/providers/downloads/StorageUtils.java
+++ b/src/com/android/providers/downloads/StorageUtils.java
@@ -16,185 +16,24 @@
package com.android.providers.downloads;
-import static android.net.TrafficStats.MB_IN_BYTES;
-import static android.provider.Downloads.Impl.STATUS_INSUFFICIENT_SPACE_ERROR;
-import static android.text.format.DateUtils.DAY_IN_MILLIS;
-import static com.android.providers.downloads.Constants.TAG;
-
import android.app.DownloadManager;
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.Context;
-import android.content.pm.IPackageDataObserver;
-import android.content.pm.PackageManager;
-import android.database.Cursor;
-import android.os.Environment;
-import android.provider.Downloads;
import android.system.ErrnoException;
import android.system.Os;
import android.system.StructStat;
-import android.system.StructStatVfs;
-import android.text.TextUtils;
-import android.util.Slog;
-import com.android.internal.annotations.VisibleForTesting;
import com.google.android.collect.Lists;
-import com.google.android.collect.Sets;
-
-import libcore.io.IoUtils;
import java.io.File;
-import java.io.FileDescriptor;
-import java.io.IOException;
import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
/**
* Utility methods for managing storage space related to
* {@link DownloadManager}.
*/
public class StorageUtils {
-
- /**
- * Minimum age for a file to be considered for deletion.
- */
- static final long MIN_DELETE_AGE = DAY_IN_MILLIS;
-
- /**
- * Reserved disk space to avoid filling disk.
- */
- static final long RESERVED_BYTES = 32 * MB_IN_BYTES;
-
- @VisibleForTesting
- static boolean sForceFullEviction = false;
-
- /**
- * Ensure that requested free space exists on the partition backing the
- * given {@link FileDescriptor}. If not enough space is available, it tries
- * freeing up space as follows:
- * <ul>
- * <li>If backed by the data partition (including emulated external
- * storage), then ask {@link PackageManager} to free space from cache
- * directories.
- * <li>If backed by the cache partition, then try deleting older downloads
- * to free space.
- * </ul>
- */
- public static void ensureAvailableSpace(Context context, FileDescriptor fd, long bytes)
- throws IOException, StopRequestException {
-
- long availBytes = getAvailableBytes(fd);
- if (availBytes >= bytes) {
- // Underlying partition has enough space; go ahead
- return;
- }
-
- // Not enough space, let's try freeing some up. Start by tracking down
- // the backing partition.
- final long dev;
- try {
- dev = Os.fstat(fd).st_dev;
- } catch (ErrnoException e) {
- throw e.rethrowAsIOException();
- }
-
- // TODO: teach about evicting caches on adopted secondary storage devices
- final long dataDev = getDeviceId(Environment.getDataDirectory());
- final long cacheDev = getDeviceId(Environment.getDownloadCacheDirectory());
- final long externalDev = getDeviceId(Environment.getExternalStorageDirectory());
-
- if (dev == dataDev || (dev == externalDev && Environment.isExternalStorageEmulated())) {
- // File lives on internal storage; ask PackageManager to try freeing
- // up space from cache directories.
- final PackageManager pm = context.getPackageManager();
- final ObserverLatch observer = new ObserverLatch();
- pm.freeStorageAndNotify(sForceFullEviction ? Long.MAX_VALUE : bytes, observer);
-
- try {
- if (!observer.latch.await(30, TimeUnit.SECONDS)) {
- throw new IOException("Timeout while freeing disk space");
- }
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
-
- } else if (dev == cacheDev) {
- // Try removing old files on cache partition
- freeCacheStorage(bytes);
- }
-
- // Did we free enough space?
- availBytes = getAvailableBytes(fd);
- if (availBytes < bytes) {
- throw new StopRequestException(STATUS_INSUFFICIENT_SPACE_ERROR,
- "Not enough free space; " + bytes + " requested, " + availBytes + " available");
- }
- }
-
- /**
- * Free requested space on cache partition, deleting oldest files first.
- * We're only focused on freeing up disk space, and rely on the next orphan
- * pass to clean up database entries.
- */
- private static void freeCacheStorage(long bytes) {
- // Only consider finished downloads
- final List<ConcreteFile> files = listFilesRecursive(
- Environment.getDownloadCacheDirectory(), Constants.DIRECTORY_CACHE_RUNNING,
- android.os.Process.myUid());
-
- Slog.d(TAG, "Found " + files.size() + " downloads on cache");
-
- Collections.sort(files, new Comparator<ConcreteFile>() {
- @Override
- public int compare(ConcreteFile lhs, ConcreteFile rhs) {
- return Long.compare(lhs.file.lastModified(), rhs.file.lastModified());
- }
- });
-
- final long now = System.currentTimeMillis();
- for (ConcreteFile file : files) {
- if (bytes <= 0) break;
-
- if (now - file.file.lastModified() < MIN_DELETE_AGE) {
- Slog.d(TAG, "Skipping recently modified " + file.file);
- } else {
- final long len = file.file.length();
- Slog.d(TAG, "Deleting " + file.file + " to reclaim " + len);
- bytes -= len;
- file.file.delete();
- }
- }
- }
-
- /**
- * Return number of available bytes on the filesystem backing the given
- * {@link FileDescriptor}, minus any {@link #RESERVED_BYTES} buffer.
- */
- private static long getAvailableBytes(FileDescriptor fd) throws IOException {
- try {
- final StructStatVfs stat = Os.fstatvfs(fd);
- return (stat.f_bavail * stat.f_bsize) - RESERVED_BYTES;
- } catch (ErrnoException e) {
- throw e.rethrowAsIOException();
- }
- }
-
- private static long getDeviceId(File file) {
- try {
- return Os.stat(file.getAbsolutePath()).st_dev;
- } catch (ErrnoException e) {
- // Safe since dev_t is uint
- return -1;
- }
- }
-
/**
* Return list of all normal files under the given directory, traversing
* directories recursively.
@@ -260,13 +99,4 @@ public class StorageUtils {
return false;
}
}
-
- static class ObserverLatch extends IPackageDataObserver.Stub {
- public final CountDownLatch latch = new CountDownLatch(1);
-
- @Override
- public void onRemoveCompleted(String packageName, boolean succeeded) {
- latch.countDown();
- }
- }
}
diff --git a/src/com/android/providers/downloads/SystemFacade.java b/src/com/android/providers/downloads/SystemFacade.java
index c34317cb..53d14041 100644
--- a/src/com/android/providers/downloads/SystemFacade.java
+++ b/src/com/android/providers/downloads/SystemFacade.java
@@ -20,6 +20,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Network;
+import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import java.security.GeneralSecurityException;
@@ -35,6 +36,8 @@ interface SystemFacade {
public NetworkInfo getNetworkInfo(Network network, int uid, boolean ignoreBlocked);
+ public boolean isNetworkMetered(Network network);
+
/**
* @return maximum size, in bytes, of downloads that may go over a mobile connection; or null if
* there's no limit
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index ec73ca2e..0f4166f5 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -21,7 +21,7 @@
<uses-permission android:name="android.permission.ACCESS_DOWNLOAD_MANAGER_ADVANCED" />
- <application>
+ <application android:usesCleartextTraffic="true">
<uses-library android:name="android.test.runner" />
</application>
diff --git a/tests/src/com/android/providers/downloads/AbstractDownloadProviderFunctionalTest.java b/tests/src/com/android/providers/downloads/AbstractDownloadProviderFunctionalTest.java
index 813252a8..13d2c36e 100644
--- a/tests/src/com/android/providers/downloads/AbstractDownloadProviderFunctionalTest.java
+++ b/tests/src/com/android/providers/downloads/AbstractDownloadProviderFunctionalTest.java
@@ -171,8 +171,8 @@ public abstract class AbstractDownloadProviderFunctionalTest extends
Helpers.setSystemFacade(mSystemFacade);
mSystemFacade.setUp();
- assertTrue(isDatabaseEmpty()); // ensure we're not messing with real data
- assertTrue(isDatabaseSecureAgainstBadSelection());
+ assertDatabaseEmpty(); // ensure we're not messing with real data
+ assertDatabaseSecureAgainstBadSelection();
mServer = new MockWebServer();
mServer.play();
}
@@ -188,34 +188,23 @@ public abstract class AbstractDownloadProviderFunctionalTest extends
protected void startDownload(long id) {
final JobParameters params = mock(JobParameters.class);
when(params.getJobId()).thenReturn((int) id);
+ getService().onBind(null);
getService().onStartJob(params);
}
- private boolean isDatabaseEmpty() {
- Cursor cursor = mResolver.query(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI,
- null, null, null, null);
- try {
- return cursor.getCount() == 0;
- } finally {
- cursor.close();
+ private void assertDatabaseEmpty() {
+ try (Cursor cursor = mResolver.query(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI,
+ null, null, null, null)) {
+ assertEquals(0, cursor.getCount());
}
}
- private boolean isDatabaseSecureAgainstBadSelection() {
- Cursor cursor = null;
- try {
- cursor = mResolver.query(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, null,
- "('1'='1'))) ORDER BY lastmod DESC--", null, null);
+ private void assertDatabaseSecureAgainstBadSelection() {
+ try (Cursor cursor = mResolver.query(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, null,
+ "('1'='1'))) ORDER BY lastmod DESC--", null, null)) {
+ fail("Database isn't secure!");
+ } catch (Exception expected) {
}
- catch (Exception e) {
- return true;
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
-
- return false;
}
/**
diff --git a/tests/src/com/android/providers/downloads/FakeSystemFacade.java b/tests/src/com/android/providers/downloads/FakeSystemFacade.java
index b6b800a2..de483c7f 100644
--- a/tests/src/com/android/providers/downloads/FakeSystemFacade.java
+++ b/tests/src/com/android/providers/downloads/FakeSystemFacade.java
@@ -1,6 +1,6 @@
package com.android.providers.downloads;
-import static org.mockito.Matchers.any;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -21,6 +21,7 @@ import java.net.URLConnection;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.List;
+
import javax.net.ssl.SSLContext;
public class FakeSystemFacade implements SystemFacade {
@@ -91,12 +92,16 @@ public class FakeSystemFacade implements SystemFacade {
final NetworkInfo info = new NetworkInfo(mActiveNetworkType, 0, null, null);
info.setDetailedState(DetailedState.CONNECTED, null, null);
info.setRoaming(mIsRoaming);
- info.setMetered(mIsMetered);
return info;
}
}
@Override
+ public boolean isNetworkMetered(Network network) {
+ return mIsMetered;
+ }
+
+ @Override
public long getMaxBytesOverMobile() {
return mMaxBytesOverMobile;
}
diff --git a/tests/src/com/android/providers/downloads/StorageTest.java b/tests/src/com/android/providers/downloads/StorageTest.java
deleted file mode 100644
index 95bd3676..00000000
--- a/tests/src/com/android/providers/downloads/StorageTest.java
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * Copyright (C) 2014 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 com.android.providers.downloads;
-
-import static android.app.DownloadManager.COLUMN_REASON;
-import static android.app.DownloadManager.ERROR_INSUFFICIENT_SPACE;
-import static android.app.DownloadManager.STATUS_FAILED;
-import static android.app.DownloadManager.STATUS_SUCCESSFUL;
-import static android.provider.Downloads.Impl.DESTINATION_CACHE_PARTITION;
-import static android.provider.Downloads.Impl.DESTINATION_SYSTEMCACHE_PARTITION;
-
-import android.app.DownloadManager;
-import android.content.pm.PackageManager;
-import android.os.Environment;
-import android.os.StatFs;
-import android.provider.Downloads.Impl;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.StructStatVfs;
-import android.test.MoreAsserts;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.util.Log;
-
-import com.android.providers.downloads.StorageUtils.ObserverLatch;
-import com.google.mockwebserver.MockResponse;
-import com.google.mockwebserver.SocketPolicy;
-
-import libcore.io.ForwardingOs;
-import libcore.io.IoUtils;
-
-import java.io.File;
-import java.io.FileDescriptor;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.concurrent.TimeUnit;
-
-@MediumTest
-public class StorageTest extends AbstractPublicApiTest {
- private static final String TAG = "StorageTest";
-
- private static final int DOWNLOAD_SIZE = 512 * 1024;
- private static final byte[] DOWNLOAD_BODY;
-
- static {
- DOWNLOAD_BODY = new byte[DOWNLOAD_SIZE];
- for (int i = 0; i < DOWNLOAD_SIZE; i++) {
- DOWNLOAD_BODY[i] = (byte) (i % 32);
- }
- }
-
- private libcore.io.Os mOriginal;
- private long mStealBytes;
-
- public StorageTest() {
- super(new FakeSystemFacade());
- }
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- StorageUtils.sForceFullEviction = true;
- mStealBytes = 0;
-
- mOriginal = libcore.io.Libcore.os;
- libcore.io.Libcore.os = new ForwardingOs(mOriginal) {
- @Override
- public StructStatVfs statvfs(String path) throws ErrnoException {
- return stealBytes(os.statvfs(path));
- }
-
- @Override
- public StructStatVfs fstatvfs(FileDescriptor fd) throws ErrnoException {
- return stealBytes(os.fstatvfs(fd));
- }
-
- private StructStatVfs stealBytes(StructStatVfs s) {
- final long stealBlocks = (mStealBytes + (s.f_bsize - 1)) / s.f_bsize;
- final long f_bavail = s.f_bavail - stealBlocks;
- return new StructStatVfs(s.f_bsize, s.f_frsize, s.f_blocks, s.f_bfree, f_bavail,
- s.f_files, s.f_ffree, s.f_favail, s.f_fsid, s.f_flag, s.f_namemax);
- }
- };
- }
-
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
-
- StorageUtils.sForceFullEviction = false;
- mStealBytes = 0;
-
- if (mOriginal != null) {
- libcore.io.Libcore.os = mOriginal;
- }
- }
-
- private enum CacheStatus { CLEAN, DIRTY }
- private enum BodyType { COMPLETE, CHUNKED }
-
- public void testDataDirtyComplete() throws Exception {
- prepareAndRunDownload(DESTINATION_CACHE_PARTITION,
- CacheStatus.DIRTY, BodyType.COMPLETE,
- STATUS_SUCCESSFUL, -1);
- }
-
- public void testDataDirtyChunked() throws Exception {
- prepareAndRunDownload(DESTINATION_CACHE_PARTITION,
- CacheStatus.DIRTY, BodyType.CHUNKED,
- STATUS_SUCCESSFUL, -1);
- }
-
- public void testDataCleanComplete() throws Exception {
- prepareAndRunDownload(DESTINATION_CACHE_PARTITION,
- CacheStatus.CLEAN, BodyType.COMPLETE,
- STATUS_FAILED, ERROR_INSUFFICIENT_SPACE);
- }
-
- public void testDataCleanChunked() throws Exception {
- prepareAndRunDownload(DESTINATION_CACHE_PARTITION,
- CacheStatus.CLEAN, BodyType.CHUNKED,
- STATUS_FAILED, ERROR_INSUFFICIENT_SPACE);
- }
-
- public void testCacheDirtyComplete() throws Exception {
- prepareAndRunDownload(DESTINATION_SYSTEMCACHE_PARTITION,
- CacheStatus.DIRTY, BodyType.COMPLETE,
- STATUS_SUCCESSFUL, -1);
- }
-
- public void testCacheDirtyChunked() throws Exception {
- prepareAndRunDownload(DESTINATION_SYSTEMCACHE_PARTITION,
- CacheStatus.DIRTY, BodyType.CHUNKED,
- STATUS_SUCCESSFUL, -1);
- }
-
- public void testCacheCleanComplete() throws Exception {
- prepareAndRunDownload(DESTINATION_SYSTEMCACHE_PARTITION,
- CacheStatus.CLEAN, BodyType.COMPLETE,
- STATUS_FAILED, ERROR_INSUFFICIENT_SPACE);
- }
-
- public void testCacheCleanChunked() throws Exception {
- prepareAndRunDownload(DESTINATION_SYSTEMCACHE_PARTITION,
- CacheStatus.CLEAN, BodyType.CHUNKED,
- STATUS_FAILED, ERROR_INSUFFICIENT_SPACE);
- }
-
- private void prepareAndRunDownload(
- int dest, CacheStatus cache, BodyType body, int expectedStatus, int expectedReason)
- throws Exception {
-
- // Ensure that we've purged everything possible for destination
- final File dirtyDir;
- if (dest == DESTINATION_CACHE_PARTITION) {
- final PackageManager pm = getContext().getPackageManager();
- final ObserverLatch observer = new ObserverLatch();
- pm.freeStorageAndNotify(Long.MAX_VALUE, observer);
-
- try {
- if (!observer.latch.await(30, TimeUnit.SECONDS)) {
- throw new IOException("Timeout while freeing disk space");
- }
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
-
- dirtyDir = getContext().getCacheDir();
-
- } else if (dest == DESTINATION_SYSTEMCACHE_PARTITION) {
- IoUtils.deleteContents(Environment.getDownloadCacheDirectory());
- dirtyDir = Environment.getDownloadCacheDirectory();
-
- } else {
- throw new IllegalArgumentException("Unknown destination");
- }
-
- // Allocate a cache file, if requested, making it large enough and old
- // enough to clear.
- final File dirtyFile;
- if (cache == CacheStatus.DIRTY) {
- dirtyFile = new File(dirtyDir, "cache_file.bin");
- assertTrue(dirtyFile.createNewFile());
- final FileOutputStream os = new FileOutputStream(dirtyFile);
- final int dirtySize = (DOWNLOAD_SIZE * 3) / 2;
- Os.posix_fallocate(os.getFD(), 0, dirtySize);
- IoUtils.closeQuietly(os);
-
- dirtyFile.setLastModified(
- System.currentTimeMillis() - (StorageUtils.MIN_DELETE_AGE * 2));
- } else {
- dirtyFile = null;
- }
-
- // At this point, hide all other disk space to make the download fail;
- // if we have a dirty cache file it can be cleared to let us proceed.
- final long targetFree = StorageUtils.RESERVED_BYTES + (DOWNLOAD_SIZE / 2);
-
- final StatFs stat = new StatFs(dirtyDir.getAbsolutePath());
- Log.d(TAG, "Available bytes (before steal): " + stat.getAvailableBytes());
- mStealBytes = stat.getAvailableBytes() - targetFree;
-
- stat.restat(dirtyDir.getAbsolutePath());
- Log.d(TAG, "Available bytes (after steal): " + stat.getAvailableBytes());
-
- final MockResponse resp = new MockResponse().setResponseCode(200)
- .setHeader("Content-type", "text/plain")
- .setSocketPolicy(SocketPolicy.DISCONNECT_AT_END);
- if (body == BodyType.CHUNKED) {
- resp.setChunkedBody(DOWNLOAD_BODY, 1021);
- } else {
- resp.setBody(DOWNLOAD_BODY);
- }
- enqueueResponse(resp);
-
- final DownloadManager.Request req = getRequest();
- if (dest == Impl.DESTINATION_SYSTEMCACHE_PARTITION) {
- req.setDestinationToSystemCache();
- }
- final Download download = enqueueRequest(req);
- download.runUntilStatus(expectedStatus);
-
- if (expectedStatus == STATUS_SUCCESSFUL) {
- MoreAsserts.assertEquals(DOWNLOAD_BODY, download.getRawContents());
- }
-
- if (expectedReason != -1) {
- assertEquals(expectedReason, download.getLongField(COLUMN_REASON));
- }
-
- if (dirtyFile != null) {
- assertFalse(dirtyFile.exists());
- }
- }
-}