Loading telephony/java/android/telephony/MbmsDownloadManager.java +54 −14 Original line number Diff line number Diff line Loading @@ -388,21 +388,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) { Loading Loading @@ -435,6 +424,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; } Loading Loading @@ -518,4 +508,54 @@ public class MbmsDownloadManager { Log.i(LOG_TAG, "Remote exception while disposing of service"); } } private void writeDownloadRequestToken(DownloadRequest request) { // TODO: figure out when this token eventually gets deleted File tempFileLocation = MbmsUtils.getEmbmsTempFileDirForRequest(mContext, request); 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."); } } } } telephony/java/android/telephony/mbms/DownloadRequest.java +55 −2 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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); } } Loading @@ -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; Loading @@ -92,6 +106,7 @@ public class DownloadRequest implements Parcelable { subscriptionId = sub; serializedResultIntentForApp = appIntent; appName = name; this.version = version; } public static DownloadRequest copy(DownloadRequest other) { Loading @@ -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) { Loading @@ -116,6 +132,7 @@ public class DownloadRequest implements Parcelable { subscriptionId = in.readInt(); serializedResultIntentForApp = in.readString(); appName = in.readString(); version = in.readInt(); } public int describeContents() { Loading @@ -130,6 +147,7 @@ public class DownloadRequest implements Parcelable { out.writeInt(subscriptionId); out.writeString(serializedResultIntentForApp); out.writeString(appName); out.writeInt(version); } public int getDownloadId() { Loading Loading @@ -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) { Loading @@ -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); } } telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java +17 −17 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ import java.util.UUID; public class MbmsDownloadReceiver extends BroadcastReceiver { private static final String LOG_TAG = "MbmsDownloadReceiver"; private static final String TEMP_FILE_SUFFIX = ".embms.temp"; public static final String DOWNLOAD_TOKEN_SUFFIX = ".download_token"; private static final int MAX_TEMP_FILE_RETRIES = 5; public static final String MBMS_FILE_PROVIDER_META_DATA_KEY = "mbms-file-provider-authority"; Loading @@ -50,7 +51,7 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (!verifyIntentContents(intent)) { if (!verifyIntentContents(context, intent)) { setResultCode(1 /* TODO: define error constants */); return; } Loading @@ -69,7 +70,7 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { // 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."); Loading @@ -93,8 +94,19 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { "temp file. Ignoring."); return false; } DownloadRequest request = intent.getParcelableExtra(MbmsDownloadManager.EXTRA_REQUEST); String expectedTokenFileName = request.getHash() + DOWNLOAD_TOKEN_SUFFIX; File expectedTokenFile = new File( MbmsUtils.getEmbmsTempFileDirForRequest(context, request), expectedTokenFileName); if (!expectedTokenFile.exists()) { Log.w(LOG_TAG, "Supplied download request does not match a token that we have. " + "Expected " + expectedTokenFile); return false; } return true; } else if (MbmsDownloadManager.ACTION_FILE_DESCRIPTOR_REQUEST.equals(intent.getAction())) { // TODO: get rid of the request argument for a file descriptor request. if (!intent.hasExtra(MbmsDownloadManager.EXTRA_REQUEST)) { Log.w(LOG_TAG, "Temp file request not include the associated request. Ignoring."); return false; Loading @@ -112,7 +124,6 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { 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, Loading Loading @@ -149,7 +160,6 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { } 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."); Loading Loading @@ -199,7 +209,7 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { private ArrayList<UriPathPair> generateFreshTempFiles(Context context, DownloadRequest request, int freshFdCount) { File tempFileDir = getEmbmsTempFileDirForRequest(context, request); File tempFileDir = MbmsUtils.getEmbmsTempFileDirForRequest(context, request); if (!tempFileDir.exists()) { tempFileDir.mkdirs(); } Loading Loading @@ -345,24 +355,14 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { return false; } if (!MbmsUtils.isContainedIn(getEmbmsTempFileDirForRequest(context, request), tempFile)) { if (!MbmsUtils.isContainedIn( MbmsUtils.getEmbmsTempFileDirForRequest(context, request), 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; Loading telephony/java/android/telephony/mbms/MbmsUtils.java +10 −0 Original line number Diff line number Diff line Loading @@ -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 request */ public static File getEmbmsTempFileDirForRequest(Context context, DownloadRequest request) { File embmsTempFileDir = MbmsTempFileProvider.getEmbmsTempFileDir(context); String tempFileDirName = String.valueOf(request.getFileServiceInfo().getServiceId()); return new File(embmsTempFileDir, tempFileDirName); } } Loading
telephony/java/android/telephony/MbmsDownloadManager.java +54 −14 Original line number Diff line number Diff line Loading @@ -388,21 +388,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) { Loading Loading @@ -435,6 +424,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; } Loading Loading @@ -518,4 +508,54 @@ public class MbmsDownloadManager { Log.i(LOG_TAG, "Remote exception while disposing of service"); } } private void writeDownloadRequestToken(DownloadRequest request) { // TODO: figure out when this token eventually gets deleted File tempFileLocation = MbmsUtils.getEmbmsTempFileDirForRequest(mContext, request); 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."); } } } }
telephony/java/android/telephony/mbms/DownloadRequest.java +55 −2 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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); } } Loading @@ -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; Loading @@ -92,6 +106,7 @@ public class DownloadRequest implements Parcelable { subscriptionId = sub; serializedResultIntentForApp = appIntent; appName = name; this.version = version; } public static DownloadRequest copy(DownloadRequest other) { Loading @@ -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) { Loading @@ -116,6 +132,7 @@ public class DownloadRequest implements Parcelable { subscriptionId = in.readInt(); serializedResultIntentForApp = in.readString(); appName = in.readString(); version = in.readInt(); } public int describeContents() { Loading @@ -130,6 +147,7 @@ public class DownloadRequest implements Parcelable { out.writeInt(subscriptionId); out.writeString(serializedResultIntentForApp); out.writeString(appName); out.writeInt(version); } public int getDownloadId() { Loading Loading @@ -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) { Loading @@ -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); } }
telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java +17 −17 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ import java.util.UUID; public class MbmsDownloadReceiver extends BroadcastReceiver { private static final String LOG_TAG = "MbmsDownloadReceiver"; private static final String TEMP_FILE_SUFFIX = ".embms.temp"; public static final String DOWNLOAD_TOKEN_SUFFIX = ".download_token"; private static final int MAX_TEMP_FILE_RETRIES = 5; public static final String MBMS_FILE_PROVIDER_META_DATA_KEY = "mbms-file-provider-authority"; Loading @@ -50,7 +51,7 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (!verifyIntentContents(intent)) { if (!verifyIntentContents(context, intent)) { setResultCode(1 /* TODO: define error constants */); return; } Loading @@ -69,7 +70,7 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { // 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."); Loading @@ -93,8 +94,19 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { "temp file. Ignoring."); return false; } DownloadRequest request = intent.getParcelableExtra(MbmsDownloadManager.EXTRA_REQUEST); String expectedTokenFileName = request.getHash() + DOWNLOAD_TOKEN_SUFFIX; File expectedTokenFile = new File( MbmsUtils.getEmbmsTempFileDirForRequest(context, request), expectedTokenFileName); if (!expectedTokenFile.exists()) { Log.w(LOG_TAG, "Supplied download request does not match a token that we have. " + "Expected " + expectedTokenFile); return false; } return true; } else if (MbmsDownloadManager.ACTION_FILE_DESCRIPTOR_REQUEST.equals(intent.getAction())) { // TODO: get rid of the request argument for a file descriptor request. if (!intent.hasExtra(MbmsDownloadManager.EXTRA_REQUEST)) { Log.w(LOG_TAG, "Temp file request not include the associated request. Ignoring."); return false; Loading @@ -112,7 +124,6 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { 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, Loading Loading @@ -149,7 +160,6 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { } 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."); Loading Loading @@ -199,7 +209,7 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { private ArrayList<UriPathPair> generateFreshTempFiles(Context context, DownloadRequest request, int freshFdCount) { File tempFileDir = getEmbmsTempFileDirForRequest(context, request); File tempFileDir = MbmsUtils.getEmbmsTempFileDirForRequest(context, request); if (!tempFileDir.exists()) { tempFileDir.mkdirs(); } Loading Loading @@ -345,24 +355,14 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { return false; } if (!MbmsUtils.isContainedIn(getEmbmsTempFileDirForRequest(context, request), tempFile)) { if (!MbmsUtils.isContainedIn( MbmsUtils.getEmbmsTempFileDirForRequest(context, request), 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; Loading
telephony/java/android/telephony/mbms/MbmsUtils.java +10 −0 Original line number Diff line number Diff line Loading @@ -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 request */ public static File getEmbmsTempFileDirForRequest(Context context, DownloadRequest request) { File embmsTempFileDir = MbmsTempFileProvider.getEmbmsTempFileDir(context); String tempFileDirName = String.valueOf(request.getFileServiceInfo().getServiceId()); return new File(embmsTempFileDir, tempFileDirName); } }