Merge changes from topics 'embms-cleanup-action', 'embms-download-token'
* changes: Implement the cleanup action in MbmsDownloadReceiver Add download request tokens and enforce destination clear
This commit is contained in:
@@ -166,6 +166,14 @@ public class MbmsDownloadManager {
|
||||
public static final String EXTRA_TEMP_FILES_IN_USE =
|
||||
"android.telephony.mbms.extra.TEMP_FILES_IN_USE";
|
||||
|
||||
/**
|
||||
* Extra containing an instance of {@link android.telephony.mbms.ServiceInfo}, used by
|
||||
* file-descriptor requests and cleanup requests to specify which service they want to
|
||||
* request temp files or clean up temp files for, respectively.
|
||||
*/
|
||||
public static final String EXTRA_SERVICE_INFO =
|
||||
"android.telephony.mbms.extra.SERVICE_INFO";
|
||||
|
||||
/**
|
||||
* Extra containing a single {@link Uri} indicating the location of the successfully
|
||||
* downloaded file. Set on the intent provided via
|
||||
@@ -388,21 +396,10 @@ public class MbmsDownloadManager {
|
||||
tempRootDirectory.mkdirs();
|
||||
setTempFileRootDirectory(tempRootDirectory);
|
||||
}
|
||||
|
||||
request.setAppName(mDownloadAppName);
|
||||
// Check if the request is a multipart download. If so, validate that the destination is
|
||||
// a directory that exists.
|
||||
// TODO: figure out what qualifies a request as a multipart download request.
|
||||
if (request.getSourceUri().getLastPathSegment() != null &&
|
||||
request.getSourceUri().getLastPathSegment().contains("*")) {
|
||||
File toFile = new File(request.getDestinationUri().getSchemeSpecificPart());
|
||||
if (!toFile.isDirectory()) {
|
||||
throw new IllegalArgumentException("Multipart download must specify valid " +
|
||||
"destination directory.");
|
||||
}
|
||||
}
|
||||
// TODO: check to make sure destination is clear
|
||||
// TODO: write download request token
|
||||
|
||||
checkValidDownloadDestination(request);
|
||||
writeDownloadRequestToken(request);
|
||||
try {
|
||||
downloadService.download(request, callback);
|
||||
} catch (RemoteException e) {
|
||||
@@ -435,6 +432,7 @@ public class MbmsDownloadManager {
|
||||
* <li>ERROR_MSDC_UNKNOWN_REQUEST</li>
|
||||
*/
|
||||
public int cancelDownload(DownloadRequest downloadRequest) {
|
||||
// TODO: don't forget to delete the token
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -518,4 +516,54 @@ public class MbmsDownloadManager {
|
||||
Log.i(LOG_TAG, "Remote exception while disposing of service");
|
||||
}
|
||||
}
|
||||
|
||||
private void writeDownloadRequestToken(DownloadRequest request) {
|
||||
File tempFileLocation = MbmsUtils.getEmbmsTempFileDirForService(mContext,
|
||||
request.getFileServiceInfo());
|
||||
if (!tempFileLocation.exists()) {
|
||||
tempFileLocation.mkdirs();
|
||||
}
|
||||
String downloadTokenFileName = request.getHash()
|
||||
+ MbmsDownloadReceiver.DOWNLOAD_TOKEN_SUFFIX;
|
||||
File token = new File(tempFileLocation, downloadTokenFileName);
|
||||
if (token.exists()) {
|
||||
Log.w(LOG_TAG, "Download token " + downloadTokenFileName + " already exists");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (!token.createNewFile()) {
|
||||
throw new RuntimeException("Failed to create download token for request "
|
||||
+ request);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to create download token for request " + request
|
||||
+ " due to IOException " + e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the following:
|
||||
* If a request is multi-part,
|
||||
* 1. Destination Uri must exist and be a directory
|
||||
* 2. Directory specified must contain no files.
|
||||
* Otherwise
|
||||
* 1. The file specified by the destination Uri must not exist.
|
||||
*/
|
||||
private void checkValidDownloadDestination(DownloadRequest request) {
|
||||
File toFile = new File(request.getDestinationUri().getSchemeSpecificPart());
|
||||
if (request.isMultipartDownload()) {
|
||||
if (!toFile.isDirectory()) {
|
||||
throw new IllegalArgumentException("Multipart download must specify valid " +
|
||||
"destination directory.");
|
||||
}
|
||||
if (toFile.listFiles().length > 0) {
|
||||
throw new IllegalArgumentException("Destination directory must be clear of all " +
|
||||
"files.");
|
||||
}
|
||||
} else {
|
||||
if (toFile.exists()) {
|
||||
throw new IllegalArgumentException("Destination file must not exist.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,15 +20,22 @@ import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.util.Base64;
|
||||
|
||||
import java.lang.IllegalStateException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* A Parcelable class describing a pending Cell-Broadcast download request
|
||||
* @hide
|
||||
*/
|
||||
public class DownloadRequest implements Parcelable {
|
||||
// Version code used to keep token calculation consistent.
|
||||
private static final int CURRENT_VERSION = 1;
|
||||
|
||||
/** @hide */
|
||||
public static class Builder {
|
||||
private int id;
|
||||
@@ -37,6 +44,7 @@ public class DownloadRequest implements Parcelable {
|
||||
private Uri dest;
|
||||
private int subscriptionId;
|
||||
private String appIntent;
|
||||
private int version = CURRENT_VERSION;
|
||||
|
||||
public Builder setId(int id) {
|
||||
this.id = id;
|
||||
@@ -68,9 +76,14 @@ public class DownloadRequest implements Parcelable {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setVersion(int version) {
|
||||
this.version = version;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DownloadRequest build() {
|
||||
return new DownloadRequest(id, serviceInfo, source, dest,
|
||||
subscriptionId, appIntent, null);
|
||||
subscriptionId, appIntent, null, version);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,11 +93,12 @@ public class DownloadRequest implements Parcelable {
|
||||
private final Uri destinationUri;
|
||||
private final int subscriptionId;
|
||||
private final String serializedResultIntentForApp;
|
||||
private final int version;
|
||||
private String appName; // not the Android app Name, the embms app name
|
||||
|
||||
private DownloadRequest(int id, FileServiceInfo serviceInfo,
|
||||
Uri source, Uri dest,
|
||||
int sub, String appIntent, String name) {
|
||||
int sub, String appIntent, String name, int version) {
|
||||
downloadId = id;
|
||||
fileServiceInfo = serviceInfo;
|
||||
sourceUri = source;
|
||||
@@ -92,6 +106,7 @@ public class DownloadRequest implements Parcelable {
|
||||
subscriptionId = sub;
|
||||
serializedResultIntentForApp = appIntent;
|
||||
appName = name;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public static DownloadRequest copy(DownloadRequest other) {
|
||||
@@ -106,6 +121,7 @@ public class DownloadRequest implements Parcelable {
|
||||
subscriptionId = dr.subscriptionId;
|
||||
serializedResultIntentForApp = dr.serializedResultIntentForApp;
|
||||
appName = dr.appName;
|
||||
version = dr.version;
|
||||
}
|
||||
|
||||
private DownloadRequest(Parcel in) {
|
||||
@@ -116,6 +132,7 @@ public class DownloadRequest implements Parcelable {
|
||||
subscriptionId = in.readInt();
|
||||
serializedResultIntentForApp = in.readString();
|
||||
appName = in.readString();
|
||||
version = in.readInt();
|
||||
}
|
||||
|
||||
public int describeContents() {
|
||||
@@ -130,6 +147,7 @@ public class DownloadRequest implements Parcelable {
|
||||
out.writeInt(subscriptionId);
|
||||
out.writeString(serializedResultIntentForApp);
|
||||
out.writeString(appName);
|
||||
out.writeInt(version);
|
||||
}
|
||||
|
||||
public int getDownloadId() {
|
||||
@@ -172,6 +190,10 @@ public class DownloadRequest implements Parcelable {
|
||||
return appName;
|
||||
}
|
||||
|
||||
public int getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<DownloadRequest> CREATOR =
|
||||
new Parcelable.Creator<DownloadRequest>() {
|
||||
public DownloadRequest createFromParcel(Parcel in) {
|
||||
@@ -181,4 +203,35 @@ public class DownloadRequest implements Parcelable {
|
||||
return new DownloadRequest[size];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public boolean isMultipartDownload() {
|
||||
// TODO: figure out what qualifies a request as a multipart download request.
|
||||
return getSourceUri().getLastPathSegment() != null &&
|
||||
getSourceUri().getLastPathSegment().contains("*");
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the hash string that should be used as the filename when storing a token for
|
||||
* this DownloadRequest.
|
||||
* @hide
|
||||
*/
|
||||
public String getHash() {
|
||||
MessageDigest digest;
|
||||
try {
|
||||
digest = MessageDigest.getInstance("SHA-256");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException("Could not get sha256 hash object");
|
||||
}
|
||||
if (version >= 1) {
|
||||
// Hash the source URI, destination URI, and the app intent
|
||||
digest.update(sourceUri.toString().getBytes(StandardCharsets.UTF_8));
|
||||
digest.update(destinationUri.toString().getBytes(StandardCharsets.UTF_8));
|
||||
digest.update(serializedResultIntentForApp.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
// Add updates for future versions here
|
||||
return Base64.encodeToString(digest.digest(), Base64.URL_SAFE | Base64.NO_WRAP);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,35 +28,85 @@ import android.telephony.MbmsDownloadManager;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class MbmsDownloadReceiver extends BroadcastReceiver {
|
||||
public static final String DOWNLOAD_TOKEN_SUFFIX = ".download_token";
|
||||
public static final String MBMS_FILE_PROVIDER_META_DATA_KEY = "mbms-file-provider-authority";
|
||||
|
||||
/**
|
||||
* TODO: @SystemApi all these result codes
|
||||
* Indicates that the requested operation completed without error.
|
||||
*/
|
||||
public static final int RESULT_OK = 0;
|
||||
|
||||
/**
|
||||
* Indicates that the intent sent had an invalid action. This will be the result if
|
||||
* {@link Intent#getAction()} returns anything other than
|
||||
* {@link MbmsDownloadManager#ACTION_DOWNLOAD_RESULT_INTERNAL},
|
||||
* {@link MbmsDownloadManager#ACTION_FILE_DESCRIPTOR_REQUEST}, or
|
||||
* {@link MbmsDownloadManager#ACTION_CLEANUP}.
|
||||
* This is a fatal result code and no result extras should be expected.
|
||||
*/
|
||||
public static final int RESULT_INVALID_ACTION = 1;
|
||||
|
||||
/**
|
||||
* Indicates that the intent was missing some required extras.
|
||||
* This is a fatal result code and no result extras should be expected.
|
||||
*/
|
||||
public static final int RESULT_MALFORMED_INTENT = 2;
|
||||
|
||||
/**
|
||||
* Indicates that the supplied value for {@link MbmsDownloadManager#EXTRA_TEMP_FILE_ROOT}
|
||||
* does not match what the app has stored.
|
||||
* This is a fatal result code and no result extras should be expected.
|
||||
*/
|
||||
public static final int RESULT_BAD_TEMP_FILE_ROOT = 3;
|
||||
|
||||
/**
|
||||
* Indicates that the manager was unable to move the completed download to its final location.
|
||||
* This is a fatal result code and no result extras should be expected.
|
||||
*/
|
||||
public static final int RESULT_DOWNLOAD_FINALIZATION_ERROR = 4;
|
||||
|
||||
/**
|
||||
* Indicates that the manager weas unable to generate one or more of the requested file
|
||||
* descriptors.
|
||||
* This is a non-fatal result code -- some file descriptors may still be generated, but there
|
||||
* is no guarantee that they will be the same number as requested.
|
||||
*/
|
||||
public static final int RESULT_TEMP_FILE_GENERATION_ERROR = 5;
|
||||
|
||||
private static final String LOG_TAG = "MbmsDownloadReceiver";
|
||||
private static final String TEMP_FILE_SUFFIX = ".embms.temp";
|
||||
private static final int MAX_TEMP_FILE_RETRIES = 5;
|
||||
|
||||
public static final String MBMS_FILE_PROVIDER_META_DATA_KEY = "mbms-file-provider-authority";
|
||||
|
||||
private String mFileProviderAuthorityCache = null;
|
||||
private String mMiddlewarePackageNameCache = null;
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (!verifyIntentContents(intent)) {
|
||||
setResultCode(1 /* TODO: define error constants */);
|
||||
if (!verifyIntentContents(context, intent)) {
|
||||
setResultCode(RESULT_MALFORMED_INTENT);
|
||||
return;
|
||||
}
|
||||
if (!Objects.equals(intent.getStringExtra(MbmsDownloadManager.EXTRA_TEMP_FILE_ROOT),
|
||||
MbmsTempFileProvider.getEmbmsTempFileDir(context).getPath())) {
|
||||
setResultCode(1 /* TODO: define error constants */);
|
||||
setResultCode(RESULT_BAD_TEMP_FILE_ROOT);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -65,11 +115,14 @@ public class MbmsDownloadReceiver extends BroadcastReceiver {
|
||||
cleanupPostMove(context, intent);
|
||||
} else if (MbmsDownloadManager.ACTION_FILE_DESCRIPTOR_REQUEST.equals(intent.getAction())) {
|
||||
generateTempFiles(context, intent);
|
||||
} else if (MbmsDownloadManager.ACTION_CLEANUP.equals(intent.getAction())) {
|
||||
cleanupTempFiles(context, intent);
|
||||
} else {
|
||||
setResultCode(RESULT_INVALID_ACTION);
|
||||
}
|
||||
// TODO: Add handling for ACTION_CLEANUP
|
||||
}
|
||||
|
||||
private boolean verifyIntentContents(Intent intent) {
|
||||
private boolean verifyIntentContents(Context context, Intent intent) {
|
||||
if (MbmsDownloadManager.ACTION_DOWNLOAD_RESULT_INTERNAL.equals(intent.getAction())) {
|
||||
if (!intent.hasExtra(MbmsDownloadManager.EXTRA_RESULT)) {
|
||||
Log.w(LOG_TAG, "Download result did not include a result code. Ignoring.");
|
||||
@@ -93,26 +146,47 @@ public class MbmsDownloadReceiver extends BroadcastReceiver {
|
||||
"temp file. Ignoring.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
DownloadRequest request = intent.getParcelableExtra(MbmsDownloadManager.EXTRA_REQUEST);
|
||||
String expectedTokenFileName = request.getHash() + DOWNLOAD_TOKEN_SUFFIX;
|
||||
File expectedTokenFile = new File(
|
||||
MbmsUtils.getEmbmsTempFileDirForService(context, request.getFileServiceInfo()),
|
||||
expectedTokenFileName);
|
||||
if (!expectedTokenFile.exists()) {
|
||||
Log.w(LOG_TAG, "Supplied download request does not match a token that we have. " +
|
||||
"Expected " + expectedTokenFile);
|
||||
return false;
|
||||
}
|
||||
} else if (MbmsDownloadManager.ACTION_FILE_DESCRIPTOR_REQUEST.equals(intent.getAction())) {
|
||||
if (!intent.hasExtra(MbmsDownloadManager.EXTRA_REQUEST)) {
|
||||
Log.w(LOG_TAG, "Temp file request not include the associated request. Ignoring.");
|
||||
if (!intent.hasExtra(MbmsDownloadManager.EXTRA_SERVICE_INFO)) {
|
||||
Log.w(LOG_TAG, "Temp file request did not include the associated service info." +
|
||||
" Ignoring.");
|
||||
return false;
|
||||
}
|
||||
if (!intent.hasExtra(MbmsDownloadManager.EXTRA_TEMP_FILE_ROOT)) {
|
||||
Log.w(LOG_TAG, "Download result did not include the temp file root. Ignoring.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else if (MbmsDownloadManager.ACTION_CLEANUP.equals(intent.getAction())) {
|
||||
if (!intent.hasExtra(MbmsDownloadManager.EXTRA_SERVICE_INFO)) {
|
||||
Log.w(LOG_TAG, "Cleanup request did not include the associated service info." +
|
||||
" Ignoring.");
|
||||
return false;
|
||||
}
|
||||
if (!intent.hasExtra(MbmsDownloadManager.EXTRA_TEMP_FILE_ROOT)) {
|
||||
Log.w(LOG_TAG, "Cleanup request did not include the temp file root. Ignoring.");
|
||||
return false;
|
||||
}
|
||||
if (!intent.hasExtra(MbmsDownloadManager.EXTRA_TEMP_FILES_IN_USE)) {
|
||||
Log.w(LOG_TAG, "Cleanup request did not include the list of temp files in use. " +
|
||||
"Ignoring.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Log.w(LOG_TAG, "Received intent with unknown action: " + intent.getAction());
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void moveDownloadedFile(Context context, Intent intent) {
|
||||
DownloadRequest request = intent.getParcelableExtra(MbmsDownloadManager.EXTRA_REQUEST);
|
||||
// TODO: check request against token
|
||||
Intent intentForApp = request.getIntentForApp();
|
||||
|
||||
int result = intent.getIntExtra(MbmsDownloadManager.EXTRA_RESULT,
|
||||
@@ -127,9 +201,9 @@ public class MbmsDownloadReceiver extends BroadcastReceiver {
|
||||
|
||||
Uri destinationUri = request.getDestinationUri();
|
||||
Uri finalTempFile = intent.getParcelableExtra(MbmsDownloadManager.EXTRA_FINAL_URI);
|
||||
if (!verifyTempFilePath(context, request, finalTempFile)) {
|
||||
if (!verifyTempFilePath(context, request.getFileServiceInfo(), finalTempFile)) {
|
||||
Log.w(LOG_TAG, "Download result specified an invalid temp file " + finalTempFile);
|
||||
setResultCode(1);
|
||||
setResultCode(RESULT_DOWNLOAD_FINALIZATION_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -140,16 +214,15 @@ public class MbmsDownloadReceiver extends BroadcastReceiver {
|
||||
if (finalFileLocation == null) {
|
||||
Log.w(LOG_TAG, "Failed to move temp file to final destination");
|
||||
// TODO: how do we notify the app of this?
|
||||
setResultCode(1);
|
||||
setResultCode(RESULT_DOWNLOAD_FINALIZATION_ERROR);
|
||||
}
|
||||
intentForApp.putExtra(MbmsDownloadManager.EXTRA_COMPLETED_FILE_URI, finalFileLocation);
|
||||
|
||||
context.sendBroadcast(intentForApp);
|
||||
setResultCode(0);
|
||||
setResultCode(RESULT_OK);
|
||||
}
|
||||
|
||||
private void cleanupPostMove(Context context, Intent intent) {
|
||||
// TODO: account for in-use temp files
|
||||
DownloadRequest request = intent.getParcelableExtra(MbmsDownloadManager.EXTRA_REQUEST);
|
||||
if (request == null) {
|
||||
Log.w(LOG_TAG, "Intent does not include a DownloadRequest. Ignoring.");
|
||||
@@ -162,7 +235,7 @@ public class MbmsDownloadReceiver extends BroadcastReceiver {
|
||||
}
|
||||
|
||||
for (Uri tempFileUri : tempFiles) {
|
||||
if (verifyTempFilePath(context, request, tempFileUri)) {
|
||||
if (verifyTempFilePath(context, request.getFileServiceInfo(), tempFileUri)) {
|
||||
File tempFile = new File(tempFileUri.getSchemeSpecificPart());
|
||||
tempFile.delete();
|
||||
}
|
||||
@@ -170,11 +243,12 @@ public class MbmsDownloadReceiver extends BroadcastReceiver {
|
||||
}
|
||||
|
||||
private void generateTempFiles(Context context, Intent intent) {
|
||||
// TODO: update pursuant to final decision on temp file locations
|
||||
DownloadRequest request = intent.getParcelableExtra(MbmsDownloadManager.EXTRA_REQUEST);
|
||||
if (request == null) {
|
||||
Log.w(LOG_TAG, "Temp file request did not include the associated request. Ignoring.");
|
||||
setResultCode(1 /* TODO: define error constants */);
|
||||
FileServiceInfo serviceInfo =
|
||||
intent.getParcelableExtra(MbmsDownloadManager.EXTRA_SERVICE_INFO);
|
||||
if (serviceInfo == null) {
|
||||
Log.w(LOG_TAG, "Temp file request did not include the associated service info. " +
|
||||
"Ignoring.");
|
||||
setResultCode(RESULT_MALFORMED_INTENT);
|
||||
return;
|
||||
}
|
||||
int fdCount = intent.getIntExtra(MbmsDownloadManager.EXTRA_FD_COUNT, 0);
|
||||
@@ -182,24 +256,27 @@ public class MbmsDownloadReceiver extends BroadcastReceiver {
|
||||
|
||||
if (fdCount == 0 && (pausedList == null || pausedList.size() == 0)) {
|
||||
Log.i(LOG_TAG, "No temp files actually requested. Ending.");
|
||||
setResultCode(0);
|
||||
setResultCode(RESULT_OK);
|
||||
setResultExtras(Bundle.EMPTY);
|
||||
return;
|
||||
}
|
||||
|
||||
ArrayList<UriPathPair> freshTempFiles = generateFreshTempFiles(context, request, fdCount);
|
||||
ArrayList<UriPathPair> freshTempFiles =
|
||||
generateFreshTempFiles(context, serviceInfo, fdCount);
|
||||
ArrayList<UriPathPair> pausedFiles =
|
||||
generateUrisForPausedFiles(context, request, pausedList);
|
||||
generateUrisForPausedFiles(context, serviceInfo, pausedList);
|
||||
|
||||
Bundle result = new Bundle();
|
||||
result.putParcelableArrayList(MbmsDownloadManager.EXTRA_FREE_URI_LIST, freshTempFiles);
|
||||
result.putParcelableArrayList(MbmsDownloadManager.EXTRA_PAUSED_URI_LIST, pausedFiles);
|
||||
setResultCode(RESULT_OK);
|
||||
setResultExtras(result);
|
||||
}
|
||||
|
||||
private ArrayList<UriPathPair> generateFreshTempFiles(Context context, DownloadRequest request,
|
||||
private ArrayList<UriPathPair> generateFreshTempFiles(Context context,
|
||||
FileServiceInfo serviceInfo,
|
||||
int freshFdCount) {
|
||||
File tempFileDir = getEmbmsTempFileDirForRequest(context, request);
|
||||
File tempFileDir = MbmsUtils.getEmbmsTempFileDirForService(context, serviceInfo);
|
||||
if (!tempFileDir.exists()) {
|
||||
tempFileDir.mkdirs();
|
||||
}
|
||||
@@ -210,11 +287,11 @@ public class MbmsDownloadReceiver extends BroadcastReceiver {
|
||||
for (int i = 0; i < freshFdCount; i++) {
|
||||
File tempFile = generateSingleTempFile(tempFileDir);
|
||||
if (tempFile == null) {
|
||||
setResultCode(2 /* TODO: define error constants */);
|
||||
setResultCode(RESULT_TEMP_FILE_GENERATION_ERROR);
|
||||
Log.w(LOG_TAG, "Failed to generate a temp file. Moving on.");
|
||||
continue;
|
||||
}
|
||||
Uri fileUri = Uri.fromParts(ContentResolver.SCHEME_FILE, tempFile.getPath(), null);
|
||||
Uri fileUri = Uri.fromFile(tempFile);
|
||||
Uri contentUri = MbmsTempFileProvider.getUriForFile(
|
||||
context, getFileProviderAuthorityCached(context), tempFile);
|
||||
context.grantUriPermission(getMiddlewarePackageCached(context), contentUri,
|
||||
@@ -243,22 +320,22 @@ public class MbmsDownloadReceiver extends BroadcastReceiver {
|
||||
}
|
||||
|
||||
private ArrayList<UriPathPair> generateUrisForPausedFiles(Context context,
|
||||
DownloadRequest request, List<Uri> pausedFiles) {
|
||||
FileServiceInfo serviceInfo, List<Uri> pausedFiles) {
|
||||
if (pausedFiles == null) {
|
||||
return new ArrayList<>(0);
|
||||
}
|
||||
ArrayList<UriPathPair> result = new ArrayList<>(pausedFiles.size());
|
||||
|
||||
for (Uri fileUri : pausedFiles) {
|
||||
if (!verifyTempFilePath(context, request, fileUri)) {
|
||||
if (!verifyTempFilePath(context, serviceInfo, fileUri)) {
|
||||
Log.w(LOG_TAG, "Supplied file " + fileUri + " is not a valid temp file to resume");
|
||||
setResultCode(2 /* TODO: define error codes */);
|
||||
setResultCode(RESULT_TEMP_FILE_GENERATION_ERROR);
|
||||
continue;
|
||||
}
|
||||
File tempFile = new File(fileUri.getSchemeSpecificPart());
|
||||
if (!tempFile.exists()) {
|
||||
Log.w(LOG_TAG, "Supplied file " + fileUri + " does not exist.");
|
||||
setResultCode(2 /* TODO: define error codes */);
|
||||
setResultCode(RESULT_TEMP_FILE_GENERATION_ERROR);
|
||||
continue;
|
||||
}
|
||||
Uri contentUri = MbmsTempFileProvider.getUriForFile(
|
||||
@@ -271,6 +348,38 @@ public class MbmsDownloadReceiver extends BroadcastReceiver {
|
||||
return result;
|
||||
}
|
||||
|
||||
private void cleanupTempFiles(Context context, Intent intent) {
|
||||
FileServiceInfo serviceInfo =
|
||||
intent.getParcelableExtra(MbmsDownloadManager.EXTRA_SERVICE_INFO);
|
||||
File tempFileDir = MbmsUtils.getEmbmsTempFileDirForService(context, serviceInfo);
|
||||
List<Uri> filesInUse =
|
||||
intent.getParcelableArrayListExtra(MbmsDownloadManager.EXTRA_TEMP_FILES_IN_USE);
|
||||
File[] filesToDelete = tempFileDir.listFiles(new FileFilter() {
|
||||
@Override
|
||||
public boolean accept(File file) {
|
||||
File canonicalFile;
|
||||
try {
|
||||
canonicalFile = file.getCanonicalFile();
|
||||
} catch (IOException e) {
|
||||
Log.w(LOG_TAG, "Got IOException canonicalizing " + file + ", not deleting.");
|
||||
return false;
|
||||
}
|
||||
// Reject all files that don't match what we think a temp file should look like
|
||||
// e.g. download tokens
|
||||
if (!canonicalFile.getName().endsWith(TEMP_FILE_SUFFIX)) {
|
||||
return false;
|
||||
}
|
||||
// If any of the files in use match the uri, return false to reject it from the
|
||||
// list to delete.
|
||||
Uri fileInUseUri = Uri.fromFile(canonicalFile);
|
||||
return !filesInUse.contains(fileInUseUri);
|
||||
}
|
||||
});
|
||||
for (File fileToDelete : filesToDelete) {
|
||||
fileToDelete.delete();
|
||||
}
|
||||
}
|
||||
|
||||
private static String calculateDestinationFileRelativePath(DownloadRequest request,
|
||||
FileInfo info) {
|
||||
List<String> filePathComponents = info.getUri().getPathSegments();
|
||||
@@ -330,7 +439,7 @@ public class MbmsDownloadReceiver extends BroadcastReceiver {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean verifyTempFilePath(Context context, DownloadRequest request,
|
||||
private static boolean verifyTempFilePath(Context context, FileServiceInfo serviceInfo,
|
||||
Uri filePath) {
|
||||
// TODO: modify pursuant to final decision on temp file path scheme
|
||||
if (!ContentResolver.SCHEME_FILE.equals(filePath.getScheme())) {
|
||||
@@ -345,24 +454,14 @@ public class MbmsDownloadReceiver extends BroadcastReceiver {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!MbmsUtils.isContainedIn(getEmbmsTempFileDirForRequest(context, request), tempFile)) {
|
||||
if (!MbmsUtils.isContainedIn(
|
||||
MbmsUtils.getEmbmsTempFileDirForService(context, serviceInfo), tempFile)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a File linked to the directory used to store temp files for this request
|
||||
*/
|
||||
private static File getEmbmsTempFileDirForRequest(Context context, DownloadRequest request) {
|
||||
File embmsTempFileDir = MbmsTempFileProvider.getEmbmsTempFileDir(context);
|
||||
|
||||
// TODO: better naming scheme for temp file dirs
|
||||
String tempFileDirName = String.valueOf(request.getFileServiceInfo().getServiceId());
|
||||
return new File(embmsTempFileDir, tempFileDirName);
|
||||
}
|
||||
|
||||
private String getFileProviderAuthorityCached(Context context) {
|
||||
if (mFileProviderAuthorityCache != null) {
|
||||
return mFileProviderAuthorityCache;
|
||||
|
||||
@@ -85,4 +85,14 @@ public class MbmsUtils {
|
||||
|
||||
context.bindService(bindIntent, serviceConnection, Context.BIND_AUTO_CREATE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a File linked to the directory used to store temp files for this file service
|
||||
*/
|
||||
public static File getEmbmsTempFileDirForService(Context context, FileServiceInfo serviceInfo) {
|
||||
File embmsTempFileDir = MbmsTempFileProvider.getEmbmsTempFileDir(context);
|
||||
|
||||
String tempFileDirName = String.valueOf(serviceInfo.getServiceId());
|
||||
return new File(embmsTempFileDir, tempFileDirName);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user