From 4343998de357d78e04449539ecb12db3257adfb9 Mon Sep 17 00:00:00 2001 From: Hall Liu Date: Wed, 15 Apr 2020 17:27:47 -0700 Subject: [PATCH] Add the addServiceAnnouncement API for EMBMS Add addServiceAnnouncement to MbmsDownloadSession, allowing apps to add service announcements from group call servers and receive information about available files via the MbmsDownloadSession API surface. Fixes: 144368478 Test: CTS Change-Id: I760400f56219879fe71d0115042a3be2f83cef90 Merged-In: I760400f56219879fe71d0115042a3be2f83cef90 --- api/current.txt | 3 + api/system-current.txt | 1 + api/test-current.txt | 1 + .../telephony/MbmsDownloadSession.java | 66 +++++++++++++++++++ .../android/telephony/mbms/MbmsErrors.java | 41 ++++++++++++ .../mbms/vendor/IMbmsDownloadService.aidl | 2 + .../mbms/vendor/MbmsDownloadServiceBase.java | 22 +++++++ 7 files changed, 136 insertions(+) diff --git a/api/current.txt b/api/current.txt index bf78391350792..5ca2969c73b05 100644 --- a/api/current.txt +++ b/api/current.txt @@ -45340,12 +45340,14 @@ package android.telephony { public class MbmsDownloadSession implements java.lang.AutoCloseable { method public void addProgressListener(@NonNull android.telephony.mbms.DownloadRequest, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.mbms.DownloadProgressListener); + method public void addServiceAnnouncementFile(@NonNull byte[]); method public void addStatusListener(@NonNull android.telephony.mbms.DownloadRequest, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.mbms.DownloadStatusListener); method public void cancelDownload(@NonNull android.telephony.mbms.DownloadRequest); method public void close(); method public static android.telephony.MbmsDownloadSession create(@NonNull android.content.Context, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.mbms.MbmsDownloadSessionCallback); method @Nullable public static android.telephony.MbmsDownloadSession create(@NonNull android.content.Context, @NonNull java.util.concurrent.Executor, int, @NonNull android.telephony.mbms.MbmsDownloadSessionCallback); method public void download(@NonNull android.telephony.mbms.DownloadRequest); + method public static int getMaximumServiceAnnouncementFileSize(); method @Nullable public java.io.File getTempFileRootDirectory(); method @NonNull public java.util.List listPendingDownloads(); method public void removeProgressListener(@NonNull android.telephony.mbms.DownloadRequest, @NonNull android.telephony.mbms.DownloadProgressListener); @@ -46956,6 +46958,7 @@ package android.telephony.mbms { public static class MbmsErrors.DownloadErrors { field public static final int ERROR_CANNOT_CHANGE_TEMP_FILE_ROOT = 401; // 0x191 + field public static final int ERROR_MALFORMED_SERVICE_ANNOUNCEMENT_FILE = 404; // 0x194 field public static final int ERROR_UNKNOWN_DOWNLOAD_REQUEST = 402; // 0x192 field public static final int ERROR_UNKNOWN_FILE_INFO = 403; // 0x193 } diff --git a/api/system-current.txt b/api/system-current.txt index 3b349bf6a9bb6..4a1bf0d803a6e 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -10320,6 +10320,7 @@ package android.telephony.mbms.vendor { public class MbmsDownloadServiceBase extends android.os.Binder implements android.os.IInterface { ctor public MbmsDownloadServiceBase(); method public int addProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener) throws android.os.RemoteException; + method public int addServiceAnnouncementFile(int, @NonNull byte[]); method public int addStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener) throws android.os.RemoteException; method public android.os.IBinder asBinder(); method public int cancelDownload(android.telephony.mbms.DownloadRequest) throws android.os.RemoteException; diff --git a/api/test-current.txt b/api/test-current.txt index 31b4ca82c68e9..d3e1e8c4c2bcb 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -4098,6 +4098,7 @@ package android.telephony.mbms.vendor { public class MbmsDownloadServiceBase extends android.os.Binder implements android.os.IInterface { ctor public MbmsDownloadServiceBase(); method public int addProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener) throws android.os.RemoteException; + method public int addServiceAnnouncementFile(int, @NonNull byte[]); method public int addStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener) throws android.os.RemoteException; method public android.os.IBinder asBinder(); method public int cancelDownload(android.telephony.mbms.DownloadRequest) throws android.os.RemoteException; diff --git a/telephony/java/android/telephony/MbmsDownloadSession.java b/telephony/java/android/telephony/MbmsDownloadSession.java index 45deea206cfc5..3d96fc634d6a1 100644 --- a/telephony/java/android/telephony/MbmsDownloadSession.java +++ b/telephony/java/android/telephony/MbmsDownloadSession.java @@ -231,6 +231,8 @@ public class MbmsDownloadSession implements AutoCloseable { private static final String DESTINATION_SANITY_CHECK_FILE_NAME = "destinationSanityCheckFile"; + private static final int MAX_SERVICE_ANNOUNCEMENT_FILE_SIZE = 10 * 1024; // 10KB + private static AtomicBoolean sIsInitialized = new AtomicBoolean(false); private final Context mContext; @@ -318,6 +320,16 @@ public class MbmsDownloadSession implements AutoCloseable { return session; } + /** + * Returns the maximum size of the service announcement file that can be provided via + * {@link #addServiceAnnouncementFile} + * @return The maximum length of the byte array passed as an argument to + * {@link #addServiceAnnouncementFile}. + */ + public static int getMaximumServiceAnnouncementFileSize() { + return MAX_SERVICE_ANNOUNCEMENT_FILE_SIZE; + } + private int bindAndInitialize() { mServiceConnection = new ServiceConnection() { @Override @@ -423,6 +435,60 @@ public class MbmsDownloadSession implements AutoCloseable { } } + /** + * Inform the middleware of a service announcement file received from a group communication + * server. + * + * When participating in a group call via the {@link MbmsGroupCallSession} API, applications may + * receive a service announcement file from the group call server that informs them of + * files that may be relevant to users communicating on the group call. + * + * After supplying the service announcement file received from the server to the middleware via + * this API, applications will receive information on the available files via + * {@link MbmsDownloadSessionCallback#onFileServicesUpdated}, and the available files will be + * downloadable via {@link MbmsDownloadSession#download} like other files published via + * {@link MbmsDownloadSessionCallback#onFileServicesUpdated}. + * + * Asynchronous error codes via the {@link MbmsDownloadSessionCallback#onError(int, String)} + * callback may include any of the errors that are not specific to the streaming use-case. + * + * May throw an {@link IllegalStateException} when the middleware has not yet been bound, + * or an {@link IllegalArgumentException} if the file is too large. + * + * @param fileContents The contents of the service announcement file received from the group + * call server. If the size of this array is greater than the value of + * {@link #getMaximumServiceAnnouncementFileSize()}, an + * {@link IllegalArgumentException} will be thrown. + */ + public void addServiceAnnouncementFile(@NonNull byte[] fileContents) { + IMbmsDownloadService downloadService = mService.get(); + if (downloadService == null) { + throw new IllegalStateException("Middleware not yet bound"); + } + + if (fileContents.length > MAX_SERVICE_ANNOUNCEMENT_FILE_SIZE) { + throw new IllegalArgumentException("File too large"); + } + + try { + int returnCode = downloadService.addServiceAnnouncementFile( + mSubscriptionId, fileContents); + if (returnCode == MbmsErrors.UNKNOWN) { + // Unbind and throw an obvious error + close(); + throw new IllegalStateException("Middleware must not return an unknown error code"); + } + if (returnCode != MbmsErrors.SUCCESS) { + sendErrorToApp(returnCode, null); + } + } catch (RemoteException e) { + Log.w(LOG_TAG, "Remote process died"); + mService.set(null); + sIsInitialized.set(false); + sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null); + } + } + /** * Sets the temp file root for downloads. * All temp files created for the middleware to write to will be contained in the specified diff --git a/telephony/java/android/telephony/mbms/MbmsErrors.java b/telephony/java/android/telephony/mbms/MbmsErrors.java index 52e4d333b29de..8611d26bc85bb 100644 --- a/telephony/java/android/telephony/mbms/MbmsErrors.java +++ b/telephony/java/android/telephony/mbms/MbmsErrors.java @@ -16,8 +16,12 @@ package android.telephony.mbms; +import android.annotation.IntDef; import android.telephony.MbmsStreamingSession; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + public class MbmsErrors { /** * Indicates that the middleware has sent an error code that is not defined in the version of @@ -138,6 +142,13 @@ public class MbmsErrors { /** Indicates the the middleware has no record of the supplied {@link FileInfo} */ public static final int ERROR_UNKNOWN_FILE_INFO = 403; + + /** + * Indicates that the service announcement file passed via + * {@link android.telephony.MbmsDownloadSession#addServiceAnnouncementFile(byte[])} + * is malformed. + */ + public static final int ERROR_MALFORMED_SERVICE_ANNOUNCEMENT_FILE = 404; } /** @@ -156,5 +167,35 @@ public class MbmsErrors { public static final int ERROR_DUPLICATE_START_GROUP_CALL = 502; } + /** @hide */ + @IntDef(value = { + SUCCESS, + ERROR_NO_UNIQUE_MIDDLEWARE, + ERROR_MIDDLEWARE_NOT_BOUND, + ERROR_MIDDLEWARE_LOST, + InitializationErrors.ERROR_DUPLICATE_INITIALIZE, + InitializationErrors.ERROR_APP_PERMISSIONS_NOT_GRANTED, + InitializationErrors.ERROR_UNABLE_TO_INITIALIZE, + GeneralErrors.ERROR_MIDDLEWARE_NOT_YET_READY, + GeneralErrors.ERROR_OUT_OF_MEMORY, + GeneralErrors.ERROR_MIDDLEWARE_TEMPORARILY_UNAVAILABLE, + GeneralErrors.ERROR_IN_E911, + GeneralErrors.ERROR_NOT_CONNECTED_TO_HOME_CARRIER_LTE, + GeneralErrors.ERROR_UNABLE_TO_READ_SIM, + GeneralErrors.ERROR_CARRIER_CHANGE_NOT_ALLOWED, + StreamingErrors.ERROR_CONCURRENT_SERVICE_LIMIT_REACHED, + StreamingErrors.ERROR_UNABLE_TO_START_SERVICE, + StreamingErrors.ERROR_DUPLICATE_START_STREAM, + DownloadErrors.ERROR_CANNOT_CHANGE_TEMP_FILE_ROOT, + DownloadErrors.ERROR_UNKNOWN_DOWNLOAD_REQUEST, + DownloadErrors.ERROR_UNKNOWN_FILE_INFO, + DownloadErrors.ERROR_MALFORMED_SERVICE_ANNOUNCEMENT_FILE, + GroupCallErrors.ERROR_UNABLE_TO_START_SERVICE, + GroupCallErrors.ERROR_DUPLICATE_START_GROUP_CALL, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface MbmsError { + } + private MbmsErrors() {} } diff --git a/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl b/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl index 445087fb78d57..36136ab280c46 100755 --- a/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl +++ b/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl @@ -35,6 +35,8 @@ interface IMbmsDownloadService int setTempFileRootDirectory(int subId, String rootDirectoryPath); + int addServiceAnnouncementFile(int subId, in byte[] fileContents); + int download(in DownloadRequest downloadRequest); int addStatusListener(in DownloadRequest downloadRequest, diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java index 9f22d0a49806b..3279ce66cd176 100644 --- a/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java +++ b/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java @@ -215,6 +215,28 @@ public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub { return 0; } + /** + * Called when the client application wishes to receive file information according to a + * service announcement file received from a group call server. + * + * The service announcement file is in the format of a multipart MIME file with XML parts, + * though no validation is performed on the contents of the {@code fileContents} argument -- + * implementing middleware applications should perform their own validation and return + * {@link MbmsErrors.DownloadErrors#ERROR_MALFORMED_SERVICE_ANNOUNCEMENT_FILE} if the file is + * malformed. + * + * @param subscriptionId The subscription id the service announcement applies to. + * @param fileContents The contents of the service announcement file. + * @return {@link MbmsErrors#SUCCESS}, or + * {@link MbmsErrors.DownloadErrors#ERROR_MALFORMED_SERVICE_ANNOUNCEMENT_FILE} + */ + // TODO: are there any public specifications of what the file format is that I can link to? + @Override + public @MbmsErrors.MbmsError int addServiceAnnouncementFile( + int subscriptionId, @NonNull byte[] fileContents) { + return 0; + } + /** * Issues a request to download a set of files. *