From 1169bc596cece10452a078facdc6962550f01ac9 Mon Sep 17 00:00:00 2001 From: Hall Liu Date: Tue, 18 Jul 2017 11:30:27 -0700 Subject: [PATCH 1/4] Mock-un-hide the MBMS streaming APIs In AOSP, this unhid the MBMS streaming APIs and modified the vendor base classes to no longer pass raw AIDLs to the vendor code. @hide tags put back in for MR1. Bug: 30981736 Test: builds Change-Id: I861e0568e3bf9ee9a937bf6314b1fc839a31f00c Merged-In: I8dd83d01a7511968ed51a80ad358a48e50c3d1e7 --- .../telephony/MbmsStreamingManager.java | 28 ++++++- .../java/android/telephony/mbms/FileInfo.java | 4 + .../telephony/mbms/FileServiceInfo.java | 1 + .../android/telephony/mbms/MbmsException.java | 12 +-- .../mbms/MbmsStreamingManagerCallback.java | 26 ++++--- .../android/telephony/mbms/ServiceInfo.java | 72 +++++++++--------- .../telephony/mbms/StreamingService.java | 7 +- .../mbms/StreamingServiceCallback.java | 21 +++-- .../telephony/mbms/StreamingServiceInfo.java | 23 ++++-- .../mbms/vendor/MbmsStreamingServiceBase.java | 76 ++++++++++++++++++- 10 files changed, 196 insertions(+), 74 deletions(-) diff --git a/telephony/java/android/telephony/MbmsStreamingManager.java b/telephony/java/android/telephony/MbmsStreamingManager.java index 911f83f0d8f1a..80b5e1b8a9372 100644 --- a/telephony/java/android/telephony/MbmsStreamingManager.java +++ b/telephony/java/android/telephony/MbmsStreamingManager.java @@ -16,6 +16,8 @@ package android.telephony; +import android.annotation.SdkConstant; +import android.annotation.SystemApi; import android.content.ComponentName; import android.content.Context; import android.content.ServiceConnection; @@ -41,6 +43,14 @@ import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; */ public class MbmsStreamingManager { private static final String LOG_TAG = "MbmsStreamingManager"; + + /** + * Service action which must be handled by the middleware implementing the MBMS streaming + * interface. + * @hide + */ + @SystemApi + @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION) public static final String MBMS_STREAMING_SERVICE_ACTION = "android.telephony.action.EmbmsStreaming"; @@ -203,13 +213,23 @@ public class MbmsStreamingManager { return; } catch (RuntimeException e) { Log.e(LOG_TAG, "Runtime exception during initialization"); - mCallbackToApp.error( - MbmsException.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE, - e.toString()); + try { + mCallbackToApp.error( + MbmsException.InitializationErrors + .ERROR_UNABLE_TO_INITIALIZE, + e.toString()); + } catch (RemoteException e1) { + // ignore + } return; } if (result != MbmsException.SUCCESS) { - mCallbackToApp.error(result, "Error returned during initialization"); + try { + mCallbackToApp.error( + result, "Error returned during initialization"); + } catch (RemoteException e) { + // ignore + } return; } mService.set(streamingService); diff --git a/telephony/java/android/telephony/mbms/FileInfo.java b/telephony/java/android/telephony/mbms/FileInfo.java index 1b873938a3f20..b8e1c49f6b4a8 100644 --- a/telephony/java/android/telephony/mbms/FileInfo.java +++ b/telephony/java/android/telephony/mbms/FileInfo.java @@ -61,6 +61,10 @@ public class FileInfo implements Parcelable { } }; + /** + * @hide + * TODO: systemapi + */ public FileInfo(Uri uri, String mimeType, long size, byte[] md5Hash) { this.uri = uri; this.mimeType = mimeType; diff --git a/telephony/java/android/telephony/mbms/FileServiceInfo.java b/telephony/java/android/telephony/mbms/FileServiceInfo.java index 6646dc8a56dfb..8afe4d3c52302 100644 --- a/telephony/java/android/telephony/mbms/FileServiceInfo.java +++ b/telephony/java/android/telephony/mbms/FileServiceInfo.java @@ -32,6 +32,7 @@ import java.util.Map; public class FileServiceInfo extends ServiceInfo implements Parcelable { private final List files; + /** @hide TODO: systemapi */ public FileServiceInfo(Map newNames, String newClassName, List newLocales, String newServiceId, Date start, Date end, List newFiles) { diff --git a/telephony/java/android/telephony/mbms/MbmsException.java b/telephony/java/android/telephony/mbms/MbmsException.java index 8888119f90e67..f57ab105d4c74 100644 --- a/telephony/java/android/telephony/mbms/MbmsException.java +++ b/telephony/java/android/telephony/mbms/MbmsException.java @@ -31,7 +31,7 @@ public class MbmsException extends Exception { /** * Indicates that the app attempted to perform an operation on an instance of - * {@link android.telephony.MbmsDownloadManager} or + * TODO: link android.telephony.MbmsDownloadManager or * {@link android.telephony.MbmsStreamingManager} without being bound to the middleware. */ public static final int ERROR_MIDDLEWARE_NOT_BOUND = 2; @@ -47,7 +47,7 @@ public class MbmsException extends Exception { /** * Indicates that the app tried to create more than one instance each of * {@link android.telephony.MbmsStreamingManager} or - * {@link android.telephony.MbmsDownloadManager}. + * TODO: link android.telephony.MbmsDownloadManager */ public static final int ERROR_DUPLICATE_INITIALIZE = 101; /** Indicates that the app is not authorized to access media via MBMS.*/ @@ -64,7 +64,7 @@ public class MbmsException extends Exception { /** * Indicates that the app attempted to perform an operation before receiving notification * that the middleware is ready via {@link MbmsStreamingManagerCallback#middlewareReady()} - * or {@link MbmsDownloadManagerCallback#middlewareReady()}. + * or TODO: link MbmsDownloadManagerCallback#middlewareReady */ public static final int ERROR_MIDDLEWARE_NOT_YET_READY = 201; /** @@ -113,6 +113,8 @@ public class MbmsException extends Exception { /** * Indicates the errors that are applicable only to the file-download use-case + * TODO: unhide + * @hide */ public static class DownloadErrors { /** @@ -127,9 +129,7 @@ public class MbmsException extends Exception { private final int mErrorCode; - /** @hide - * TODO: future systemapi - */ + /** @hide */ public MbmsException(int errorCode) { super(); mErrorCode = errorCode; diff --git a/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java b/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java index 2e91be9acaf7f..41bdddfafbbce 100644 --- a/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java +++ b/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java @@ -16,20 +16,25 @@ package android.telephony.mbms; +import android.content.Context; +import android.os.RemoteException; + import java.util.List; /** - * A Parcelable class with Cell-Broadcast service information. + * A callback class that is used to receive information from the middleware on MBMS streaming + * services. An instance of this object should be passed into + * {@link android.telephony.MbmsStreamingManager#create(Context, MbmsStreamingManagerCallback)}. * @hide */ public class MbmsStreamingManagerCallback extends IMbmsStreamingManagerCallback.Stub { - - public final static int ERROR_CARRIER_NOT_SUPPORTED = 1; - public final static int ERROR_UNABLE_TO_INITIALIZE = 2; - public final static int ERROR_UNABLE_TO_ALLOCATE_MEMORY = 3; - - - public void error(int errorCode, String message) { + /** + * Called by the middleware when it has detected an error condition. The possible error codes + * are listed in {@link MbmsException}. + * @param errorCode The error code. + * @param message A human-readable message generated by the middleware for debugging purposes. + */ + public void error(int errorCode, String message) throws RemoteException { // default implementation empty } @@ -45,7 +50,8 @@ public class MbmsStreamingManagerCallback extends IMbmsStreamingManagerCallback. * @param services a List of StreamingServiceInfos * */ - public void streamingServicesUpdated(List services) { + public void streamingServicesUpdated(List services) + throws RemoteException { // default implementation empty } @@ -58,7 +64,7 @@ public class MbmsStreamingManagerCallback extends IMbmsStreamingManagerCallback. * or {@link MbmsException.GeneralErrors#ERROR_MIDDLEWARE_NOT_YET_READY} */ @Override - public void middlewareReady() { + public void middlewareReady() throws RemoteException { // default implementation empty } } diff --git a/telephony/java/android/telephony/mbms/ServiceInfo.java b/telephony/java/android/telephony/mbms/ServiceInfo.java index f9ad44c63118b..e1c6183aae8c9 100644 --- a/telephony/java/android/telephony/mbms/ServiceInfo.java +++ b/telephony/java/android/telephony/mbms/ServiceInfo.java @@ -30,43 +30,22 @@ import java.util.Objects; import java.util.Set; /** - * A Parcelable class with Cell-Broadcast service information. + * Describes a cell-broadcast service. This class should not be instantiated directly -- use + * {@link StreamingServiceInfo} or FileServiceInfo TODO: add link once that's unhidden * @hide */ public class ServiceInfo implements Parcelable { // arbitrary limit on the number of locale -> name pairs we support final static int MAP_LIMIT = 1000; - /** - * User displayable names listed by language. Unmodifiable. - */ - final Map names; - - /** - * The class name for this service - used to catagorize and filter - */ - final String className; - - /** - * The languages available for this service content - */ - final List locales; - - /** - * The carrier's identifier for the service. - */ - final String serviceId; - - /** - * The start time indicating when this service will be available. - */ - final Date sessionStartTime; - - /** - * The end time indicating when this sesion stops being available. - */ - final Date sessionEndTime; + private final Map names; + private final String className; + private final List locales; + private final String serviceId; + private final Date sessionStartTime; + private final Date sessionEndTime; + /** @hide */ public ServiceInfo(Map newNames, String newClassName, List newLocales, String newServiceId, Date start, Date end) { if (newNames == null || newNames.isEmpty() || TextUtils.isEmpty(newClassName) @@ -89,20 +68,21 @@ public class ServiceInfo implements Parcelable { sessionEndTime = (Date)end.clone(); } - public static final Parcelable.Creator CREATOR = - new Parcelable.Creator() { + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { @Override - public FileServiceInfo createFromParcel(Parcel source) { - return new FileServiceInfo(source); + public ServiceInfo createFromParcel(Parcel source) { + return new ServiceInfo(source); } @Override - public FileServiceInfo[] newArray(int size) { - return new FileServiceInfo[size]; + public ServiceInfo[] newArray(int size) { + return new ServiceInfo[size]; } }; - ServiceInfo(Parcel in) { + /** @hide */ + protected ServiceInfo(Parcel in) { int mapCount = in.readInt(); if (mapCount > MAP_LIMIT || mapCount < 0) { throw new RuntimeException("bad map length" + mapCount); @@ -152,26 +132,44 @@ public class ServiceInfo implements Parcelable { return 0; } + /** + * User displayable names listed by language. Do not modify the map returned from this method. + */ public Map getNames() { return names; } + /** + * The class name for this service - used to categorize and filter + */ public String getClassName() { return className; } + /** + * The languages available for this service content + */ public List getLocales() { return locales; } + /** + * The carrier's identifier for the service. + */ public String getServiceId() { return serviceId; } + /** + * The start time indicating when this service will be available. + */ public Date getSessionStartTime() { return sessionStartTime; } + /** + * The end time indicating when this session stops being available. + */ public Date getSessionEndTime() { return sessionEndTime; } diff --git a/telephony/java/android/telephony/mbms/StreamingService.java b/telephony/java/android/telephony/mbms/StreamingService.java index c49f8a980cbba..a87e9ee5a2ced 100644 --- a/telephony/java/android/telephony/mbms/StreamingService.java +++ b/telephony/java/android/telephony/mbms/StreamingService.java @@ -26,6 +26,10 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** + * Class used to represent a single MBMS stream. After a stream has been started with + * {@link android.telephony.MbmsStreamingManager#startStreaming(StreamingServiceInfo, + * StreamingServiceCallback)}, + * this class is used to hold information about the stream and control it. * @hide */ public class StreamingService { @@ -60,7 +64,8 @@ public class StreamingService { /** * State changed due to a call to {@link #stopStreaming()} or - * {@link android.telephony.MbmsStreamingManager#startStreaming(StreamingServiceInfo, StreamingServiceCallback)} + * {@link android.telephony.MbmsStreamingManager#startStreaming(StreamingServiceInfo, + * StreamingServiceCallback)} */ public static final int REASON_BY_USER_REQUEST = 1; diff --git a/telephony/java/android/telephony/mbms/StreamingServiceCallback.java b/telephony/java/android/telephony/mbms/StreamingServiceCallback.java index cab9c23499eaf..9a62f2edcaf42 100644 --- a/telephony/java/android/telephony/mbms/StreamingServiceCallback.java +++ b/telephony/java/android/telephony/mbms/StreamingServiceCallback.java @@ -16,8 +16,11 @@ package android.telephony.mbms; +import android.os.RemoteException; + /** - * A Callback class for use when the application is actively streaming content. + * A callback class for use when the application is actively streaming content. The middleware + * will provide updates on the status of the stream via this callback. * @hide */ public class StreamingServiceCallback extends IStreamingServiceCallback.Stub { @@ -31,8 +34,14 @@ public class StreamingServiceCallback extends IStreamingServiceCallback.Stub { */ public static final int SIGNAL_STRENGTH_UNAVAILABLE = -1; + /** + * Called by the middleware when it has detected an error condition in this stream. The + * possible error codes are listed in {@link MbmsException}. + * @param errorCode The error code. + * @param message A human-readable message generated by the middleware for debugging purposes. + */ @Override - public void error(int errorCode, String message) { + public void error(int errorCode, String message) throws RemoteException { // default implementation empty } @@ -44,7 +53,7 @@ public class StreamingServiceCallback extends IStreamingServiceCallback.Stub { */ @Override public void streamStateUpdated(@StreamingService.StreamingState int state, - @StreamingService.StreamingStateChangeReason int reason) { + @StreamingService.StreamingStateChangeReason int reason) throws RemoteException { // default implementation empty } @@ -59,7 +68,7 @@ public class StreamingServiceCallback extends IStreamingServiceCallback.Stub { * when parameters have changed to account for time drift. */ @Override - public void mediaDescriptionUpdated() { + public void mediaDescriptionUpdated() throws RemoteException { // default implementation empty } @@ -74,7 +83,7 @@ public class StreamingServiceCallback extends IStreamingServiceCallback.Stub { * for this service due to timing, geography or popularity. */ @Override - public void broadcastSignalStrengthUpdated(int signalStrength) { + public void broadcastSignalStrengthUpdated(int signalStrength) throws RemoteException { // default implementation empty } @@ -95,7 +104,7 @@ public class StreamingServiceCallback extends IStreamingServiceCallback.Stub { * {@link StreamingService#UNICAST_METHOD} */ @Override - public void streamMethodUpdated(int methodType) { + public void streamMethodUpdated(int methodType) throws RemoteException { // default implementation empty } } diff --git a/telephony/java/android/telephony/mbms/StreamingServiceInfo.java b/telephony/java/android/telephony/mbms/StreamingServiceInfo.java index 77ce3bbd696e4..0d6c95c1eb014 100644 --- a/telephony/java/android/telephony/mbms/StreamingServiceInfo.java +++ b/telephony/java/android/telephony/mbms/StreamingServiceInfo.java @@ -16,6 +16,7 @@ package android.telephony.mbms; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; @@ -25,15 +26,25 @@ import java.util.Locale; import java.util.Map; /** - * A Parcelable class Cell-Broadcast media stream information. - * This may not have any more info than ServiceInfo, but kept for completeness. + * Describes a single MBMS streaming service. * @hide */ public class StreamingServiceInfo extends ServiceInfo implements Parcelable { - public StreamingServiceInfo(Map newNames, String newClassName, - List newLocales, String newServiceId, Date start, Date end) { - super(newNames, newClassName, newLocales, newServiceId, start, end); + /** + * @param names User displayable names listed by language. + * @param className The class name for this service - used by frontend apps to categorize and + * filter. + * @param locales The languages available for this service content. + * @param serviceId The carrier's identifier for the service. + * @param start The start time indicating when this service will be available. + * @param end The end time indicating when this session stops being available. + * @hide + */ + @SystemApi + public StreamingServiceInfo(Map names, String className, + List locales, String serviceId, Date start, Date end) { + super(names, className, locales, serviceId, start, end); } public static final Parcelable.Creator CREATOR = @@ -49,7 +60,7 @@ public class StreamingServiceInfo extends ServiceInfo implements Parcelable { } }; - StreamingServiceInfo(Parcel in) { + private StreamingServiceInfo(Parcel in) { super(in); } diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java index 585d5b9610b76..ab1c982fa6f8e 100644 --- a/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java +++ b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java @@ -17,18 +17,23 @@ package android.telephony.mbms.vendor; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.net.Uri; import android.os.RemoteException; import android.telephony.mbms.IMbmsStreamingManagerCallback; import android.telephony.mbms.IStreamingServiceCallback; import android.telephony.mbms.MbmsException; +import android.telephony.mbms.MbmsStreamingManagerCallback; +import android.telephony.mbms.StreamingService; +import android.telephony.mbms.StreamingServiceCallback; +import android.telephony.mbms.StreamingServiceInfo; import java.util.List; /** * @hide - * TODO: future systemapi */ +//@SystemApi public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub { /** * Initialize streaming service for this app and subId, registering the listener. @@ -44,12 +49,38 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub { * @param listener The callback to use to communicate with the app. * @param subscriptionId The subscription ID to use. */ - @Override - public int initialize(IMbmsStreamingManagerCallback listener, int subscriptionId) + public int initialize(MbmsStreamingManagerCallback listener, int subscriptionId) throws RemoteException { return 0; } + /** + * Actual AIDL implementation that hides the callback AIDL from the middleware. + * @hide + */ + @Override + public final int initialize(IMbmsStreamingManagerCallback listener, int subscriptionId) + throws RemoteException { + return initialize(new MbmsStreamingManagerCallback() { + @Override + public void error(int errorCode, String message) throws RemoteException { + listener.error(errorCode, message); + } + + @Override + public void streamingServicesUpdated(List services) throws + RemoteException { + listener.streamingServicesUpdated(services); + } + + @Override + public void middlewareReady() throws RemoteException { + listener.middlewareReady(); + } + }, subscriptionId); + } + + /** * Registers serviceClasses of interest with the appName/subId key. * Starts async fetching data on streaming services of matching classes to be reported @@ -85,10 +116,47 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub { * @param listener The listener object on which the app wishes to receive updates. * @return Any error in {@link android.telephony.mbms.MbmsException.GeneralErrors} */ + public int startStreaming(int subscriptionId, String serviceId, + StreamingServiceCallback listener) throws RemoteException { + return 0; + } + + /** + * Actual AIDL implementation of startStreaming that hides the callback AIDL from the + * middleware. + * @hide + */ @Override public int startStreaming(int subscriptionId, String serviceId, IStreamingServiceCallback listener) throws RemoteException { - return 0; + return startStreaming(subscriptionId, serviceId, new StreamingServiceCallback() { + @Override + public void error(int errorCode, String message) throws RemoteException { + listener.error(errorCode, message); + } + + @Override + public void streamStateUpdated(@StreamingService.StreamingState int state, + @StreamingService.StreamingStateChangeReason int reason) + throws RemoteException { + listener.streamStateUpdated(state, reason); + } + + @Override + public void mediaDescriptionUpdated() throws RemoteException { + listener.mediaDescriptionUpdated(); + } + + @Override + public void broadcastSignalStrengthUpdated(int signalStrength) throws RemoteException { + listener.broadcastSignalStrengthUpdated(signalStrength); + } + + @Override + public void streamMethodUpdated(int methodType) throws RemoteException { + listener.streamMethodUpdated(methodType); + } + }); } /** From 4f306dedc58c24b4e16c2418f26961d06d9a2d1a Mon Sep 17 00:00:00 2001 From: Hall Liu Date: Thu, 3 Aug 2017 18:26:39 -0700 Subject: [PATCH 2/4] Fix lint errors in the streaming API Fix the errors that cropped up when trying to upload the unhide CL in MR1. Bug: 30981736 Test: manual, with testapps Change-Id: If4a9a5533a235a8cc56762ab7a9e32ec89440f1d --- .../telephony/MbmsStreamingManager.java | 66 +++++++++---- .../InternalStreamingManagerCallback.java | 72 ++++++++++++++ .../InternalStreamingServiceCallback.java | 81 ++++++++++++++++ .../android/telephony/mbms/MbmsException.java | 8 +- .../mbms/MbmsStreamingManagerCallback.java | 10 +- .../android/telephony/mbms/ServiceInfo.java | 22 +---- .../telephony/mbms/StreamingService.java | 15 +-- .../mbms/StreamingServiceCallback.java | 21 ++-- .../telephony/mbms/StreamingServiceInfo.java | 2 +- .../mbms/vendor/MbmsStreamingServiceBase.java | 95 +++++++++++++++---- 10 files changed, 305 insertions(+), 87 deletions(-) create mode 100644 telephony/java/android/telephony/mbms/InternalStreamingManagerCallback.java create mode 100644 telephony/java/android/telephony/mbms/InternalStreamingServiceCallback.java diff --git a/telephony/java/android/telephony/MbmsStreamingManager.java b/telephony/java/android/telephony/MbmsStreamingManager.java index 80b5e1b8a9372..2fe1c6cc2e657 100644 --- a/telephony/java/android/telephony/MbmsStreamingManager.java +++ b/telephony/java/android/telephony/MbmsStreamingManager.java @@ -21,8 +21,12 @@ import android.annotation.SystemApi; import android.content.ComponentName; import android.content.Context; import android.content.ServiceConnection; +import android.os.Handler; import android.os.IBinder; +import android.os.Looper; import android.os.RemoteException; +import android.telephony.mbms.InternalStreamingManagerCallback; +import android.telephony.mbms.InternalStreamingServiceCallback; import android.telephony.mbms.MbmsException; import android.telephony.mbms.MbmsStreamingManagerCallback; import android.telephony.mbms.MbmsUtils; @@ -55,17 +59,20 @@ public class MbmsStreamingManager { "android.telephony.action.EmbmsStreaming"; private AtomicReference mService = new AtomicReference<>(null); - private MbmsStreamingManagerCallback mCallbackToApp; + private InternalStreamingManagerCallback mInternalCallback; private final Context mContext; private int mSubscriptionId = INVALID_SUBSCRIPTION_ID; /** @hide */ private MbmsStreamingManager(Context context, MbmsStreamingManagerCallback callback, - int subscriptionId) { + int subscriptionId, Handler handler) { mContext = context; - mCallbackToApp = callback; mSubscriptionId = subscriptionId; + if (handler == null) { + handler = new Handler(Looper.getMainLooper()); + } + mInternalCallback = new InternalStreamingManagerCallback(callback, handler); } /** @@ -79,23 +86,38 @@ public class MbmsStreamingManager { * @param callback A callback object on which you wish to receive results of asynchronous * operations. * @param subscriptionId The subscription ID to use. + * @param handler The handler you wish to receive callbacks on. If null, callbacks will be + * processed on the main looper (in other words, the looper returned from + * {@link Looper#getMainLooper()}). */ public static MbmsStreamingManager create(Context context, - MbmsStreamingManagerCallback callback, int subscriptionId) + MbmsStreamingManagerCallback callback, int subscriptionId, Handler handler) throws MbmsException { - MbmsStreamingManager manager = new MbmsStreamingManager(context, callback, subscriptionId); + MbmsStreamingManager manager = new MbmsStreamingManager(context, callback, + subscriptionId, handler); manager.bindAndInitialize(); return manager; } /** * Create a new MbmsStreamingManager using the system default data subscription ID. - * See {@link #create(Context, MbmsStreamingManagerCallback, int)}. + * See {@link #create(Context, MbmsStreamingManagerCallback, int, Handler)}. + */ + public static MbmsStreamingManager create(Context context, + MbmsStreamingManagerCallback callback, Handler handler) + throws MbmsException { + return create(context, callback, SubscriptionManager.getDefaultSubscriptionId(), handler); + } + + /** + * Create a new MbmsStreamingManager using the system default data subscription ID and + * default {@link Handler}. + * See {@link #create(Context, MbmsStreamingManagerCallback, int, Handler)}. */ public static MbmsStreamingManager create(Context context, MbmsStreamingManagerCallback callback) throws MbmsException { - return create(context, callback, SubscriptionManager.getDefaultSubscriptionId()); + return create(context, callback, SubscriptionManager.getDefaultSubscriptionId(), null); } /** @@ -154,11 +176,11 @@ public class MbmsStreamingManager { } /** - * Starts streaming a requested service, reporting status to the indicated listener. + * Starts streaming a requested service, reporting status to the indicated callback. * Returns an object used to control that stream. The stream may not be ready for consumption * immediately upon return from this method -- wait until the streaming state has been * reported via - * {@link android.telephony.mbms.StreamingServiceCallback#streamStateUpdated(int, int)} + * {@link android.telephony.mbms.StreamingServiceCallback#onStreamStateUpdated(int, int)} * * May throw an * {@link MbmsException} containing any of the error codes in @@ -168,24 +190,33 @@ public class MbmsStreamingManager { * * May also throw an {@link IllegalArgumentException} or an {@link IllegalStateException} * - * Asynchronous errors through the listener include any of the errors in + * Asynchronous errors through the callback include any of the errors in * {@link android.telephony.mbms.MbmsException.GeneralErrors} or * {@link android.telephony.mbms.MbmsException.StreamingErrors}. * * @param serviceInfo The information about the service to stream. - * @param listener A listener that'll be called when something about the stream changes. + * @param callback A callback that'll be called when something about the stream changes. + * @param handler A handler that calls to {@code callback} should be called on. If null, + * defaults to the handler provided via + * {@link #create(Context, MbmsStreamingManagerCallback, int, Handler)}. * @return An instance of {@link StreamingService} through which the stream can be controlled. */ public StreamingService startStreaming(StreamingServiceInfo serviceInfo, - StreamingServiceCallback listener) throws MbmsException { + StreamingServiceCallback callback, Handler handler) throws MbmsException { IMbmsStreamingService streamingService = mService.get(); if (streamingService == null) { throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_NOT_BOUND); } + InternalStreamingServiceCallback serviceCallback = new InternalStreamingServiceCallback( + callback, handler == null ? mInternalCallback.getHandler() : handler); + + StreamingService serviceForApp = new StreamingService( + mSubscriptionId, streamingService, serviceInfo, serviceCallback); + try { int returnCode = streamingService.startStreaming( - mSubscriptionId, serviceInfo.getServiceId(), listener); + mSubscriptionId, serviceInfo.getServiceId(), serviceCallback); if (returnCode != MbmsException.SUCCESS) { throw new MbmsException(returnCode); } @@ -195,7 +226,7 @@ public class MbmsStreamingManager { throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST); } - return new StreamingService(mSubscriptionId, streamingService, serviceInfo, listener); + return serviceForApp; } private void bindAndInitialize() throws MbmsException { @@ -207,14 +238,15 @@ public class MbmsStreamingManager { IMbmsStreamingService.Stub.asInterface(service); int result; try { - result = streamingService.initialize(mCallbackToApp, mSubscriptionId); + result = streamingService.initialize(mInternalCallback, + mSubscriptionId); } catch (RemoteException e) { Log.e(LOG_TAG, "Service died before initialization"); return; } catch (RuntimeException e) { Log.e(LOG_TAG, "Runtime exception during initialization"); try { - mCallbackToApp.error( + mInternalCallback.error( MbmsException.InitializationErrors .ERROR_UNABLE_TO_INITIALIZE, e.toString()); @@ -225,7 +257,7 @@ public class MbmsStreamingManager { } if (result != MbmsException.SUCCESS) { try { - mCallbackToApp.error( + mInternalCallback.error( result, "Error returned during initialization"); } catch (RemoteException e) { // ignore diff --git a/telephony/java/android/telephony/mbms/InternalStreamingManagerCallback.java b/telephony/java/android/telephony/mbms/InternalStreamingManagerCallback.java new file mode 100644 index 0000000000000..b52df8c0dd84f --- /dev/null +++ b/telephony/java/android/telephony/mbms/InternalStreamingManagerCallback.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2017 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 android.telephony.mbms; + +import android.os.Handler; +import android.os.RemoteException; +import android.telephony.mbms.IMbmsStreamingManagerCallback; +import android.telephony.mbms.MbmsStreamingManagerCallback; +import android.telephony.mbms.StreamingServiceInfo; + +import java.util.List; + +/** @hide */ +public class InternalStreamingManagerCallback extends IMbmsStreamingManagerCallback.Stub { + private final Handler mHandler; + private final MbmsStreamingManagerCallback mAppCallback; + + public InternalStreamingManagerCallback(MbmsStreamingManagerCallback appCallback, + Handler handler) { + mAppCallback = appCallback; + mHandler = handler; + } + + @Override + public void error(int errorCode, String message) throws RemoteException { + mHandler.post(new Runnable() { + @Override + public void run() { + mAppCallback.onError(errorCode, message); + } + }); + } + + @Override + public void streamingServicesUpdated(List services) + throws RemoteException { + mHandler.post(new Runnable() { + @Override + public void run() { + mAppCallback.onStreamingServicesUpdated(services); + } + }); + } + + @Override + public void middlewareReady() throws RemoteException { + mHandler.post(new Runnable() { + @Override + public void run() { + mAppCallback.onMiddlewareReady(); + } + }); + } + + public Handler getHandler() { + return mHandler; + } +} diff --git a/telephony/java/android/telephony/mbms/InternalStreamingServiceCallback.java b/telephony/java/android/telephony/mbms/InternalStreamingServiceCallback.java new file mode 100644 index 0000000000000..bb337b271cf0a --- /dev/null +++ b/telephony/java/android/telephony/mbms/InternalStreamingServiceCallback.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2017 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 android.telephony.mbms; + +import android.os.Handler; +import android.os.RemoteException; + +/** @hide */ +public class InternalStreamingServiceCallback extends IStreamingServiceCallback.Stub { + private final StreamingServiceCallback mAppCallback; + private final Handler mHandler; + + public InternalStreamingServiceCallback(StreamingServiceCallback appCallback, Handler handler) { + mAppCallback = appCallback; + mHandler = handler; + } + + @Override + public void error(int errorCode, String message) throws RemoteException { + mHandler.post(new Runnable() { + @Override + public void run() { + mAppCallback.onError(errorCode, message); + } + }); + } + + @Override + public void streamStateUpdated(int state, int reason) throws RemoteException { + mHandler.post(new Runnable() { + @Override + public void run() { + mAppCallback.onStreamStateUpdated(state, reason); + } + }); + } + + @Override + public void mediaDescriptionUpdated() throws RemoteException { + mHandler.post(new Runnable() { + @Override + public void run() { + mAppCallback.onMediaDescriptionUpdated(); + } + }); + } + + @Override + public void broadcastSignalStrengthUpdated(int signalStrength) throws RemoteException { + mHandler.post(new Runnable() { + @Override + public void run() { + mAppCallback.onBroadcastSignalStrengthUpdated(signalStrength); + } + }); + } + + @Override + public void streamMethodUpdated(int methodType) throws RemoteException { + mHandler.post(new Runnable() { + @Override + public void run() { + mAppCallback.onStreamMethodUpdated(methodType); + } + }); + } +} diff --git a/telephony/java/android/telephony/mbms/MbmsException.java b/telephony/java/android/telephony/mbms/MbmsException.java index f57ab105d4c74..7cf87927dca1a 100644 --- a/telephony/java/android/telephony/mbms/MbmsException.java +++ b/telephony/java/android/telephony/mbms/MbmsException.java @@ -44,6 +44,7 @@ public class MbmsException extends Exception { * middleware. They are applicable to both streaming and file-download use-cases. */ public static class InitializationErrors { + private InitializationErrors() {} /** * Indicates that the app tried to create more than one instance each of * {@link android.telephony.MbmsStreamingManager} or @@ -61,9 +62,10 @@ public class MbmsException extends Exception { * streaming and file-download. */ public static class GeneralErrors { + private GeneralErrors() {} /** * Indicates that the app attempted to perform an operation before receiving notification - * that the middleware is ready via {@link MbmsStreamingManagerCallback#middlewareReady()} + * that the middleware is ready via {@link MbmsStreamingManagerCallback#onMiddlewareReady()} * or TODO: link MbmsDownloadManagerCallback#middlewareReady */ public static final int ERROR_MIDDLEWARE_NOT_YET_READY = 201; @@ -97,6 +99,7 @@ public class MbmsException extends Exception { * Indicates the errors that are applicable only to the streaming use-case */ public static class StreamingErrors { + private StreamingErrors() {} /** Indicates that the middleware cannot start a stream due to too many ongoing streams */ public static final int ERROR_CONCURRENT_SERVICE_LIMIT_REACHED = 301; @@ -105,7 +108,8 @@ public class MbmsException extends Exception { /** * Indicates that the app called - * {@link android.telephony.MbmsStreamingManager#startStreaming(StreamingServiceInfo, StreamingServiceCallback)} + * {@link android.telephony.MbmsStreamingManager#startStreaming( + * StreamingServiceInfo, StreamingServiceCallback, android.os.Handler)} * more than once for the same {@link StreamingServiceInfo}. */ public static final int ERROR_DUPLICATE_START_STREAM = 303; diff --git a/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java b/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java index 41bdddfafbbce..b6b007bcaf5b7 100644 --- a/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java +++ b/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java @@ -27,14 +27,14 @@ import java.util.List; * {@link android.telephony.MbmsStreamingManager#create(Context, MbmsStreamingManagerCallback)}. * @hide */ -public class MbmsStreamingManagerCallback extends IMbmsStreamingManagerCallback.Stub { +public class MbmsStreamingManagerCallback { /** * Called by the middleware when it has detected an error condition. The possible error codes * are listed in {@link MbmsException}. * @param errorCode The error code. * @param message A human-readable message generated by the middleware for debugging purposes. */ - public void error(int errorCode, String message) throws RemoteException { + public void onError(int errorCode, String message) { // default implementation empty } @@ -50,8 +50,7 @@ public class MbmsStreamingManagerCallback extends IMbmsStreamingManagerCallback. * @param services a List of StreamingServiceInfos * */ - public void streamingServicesUpdated(List services) - throws RemoteException { + public void onStreamingServicesUpdated(List services) { // default implementation empty } @@ -63,8 +62,7 @@ public class MbmsStreamingManagerCallback extends IMbmsStreamingManagerCallback. * being thrown with error code {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND} * or {@link MbmsException.GeneralErrors#ERROR_MIDDLEWARE_NOT_YET_READY} */ - @Override - public void middlewareReady() throws RemoteException { + public void onMiddlewareReady() { // default implementation empty } } diff --git a/telephony/java/android/telephony/mbms/ServiceInfo.java b/telephony/java/android/telephony/mbms/ServiceInfo.java index e1c6183aae8c9..423ae01df7152 100644 --- a/telephony/java/android/telephony/mbms/ServiceInfo.java +++ b/telephony/java/android/telephony/mbms/ServiceInfo.java @@ -34,7 +34,7 @@ import java.util.Set; * {@link StreamingServiceInfo} or FileServiceInfo TODO: add link once that's unhidden * @hide */ -public class ServiceInfo implements Parcelable { +public class ServiceInfo { // arbitrary limit on the number of locale -> name pairs we support final static int MAP_LIMIT = 1000; @@ -68,19 +68,6 @@ public class ServiceInfo implements Parcelable { sessionEndTime = (Date)end.clone(); } - public static final Parcelable.Creator CREATOR = - new Parcelable.Creator() { - @Override - public ServiceInfo createFromParcel(Parcel source) { - return new ServiceInfo(source); - } - - @Override - public ServiceInfo[] newArray(int size) { - return new ServiceInfo[size]; - } - }; - /** @hide */ protected ServiceInfo(Parcel in) { int mapCount = in.readInt(); @@ -108,7 +95,7 @@ public class ServiceInfo implements Parcelable { sessionEndTime = (java.util.Date) in.readSerializable(); } - @Override + /** @hide */ public void writeToParcel(Parcel dest, int flags) { Set keySet = names.keySet(); dest.writeInt(keySet.size()); @@ -127,11 +114,6 @@ public class ServiceInfo implements Parcelable { dest.writeSerializable(sessionEndTime); } - @Override - public int describeContents() { - return 0; - } - /** * User displayable names listed by language. Do not modify the map returned from this method. */ diff --git a/telephony/java/android/telephony/mbms/StreamingService.java b/telephony/java/android/telephony/mbms/StreamingService.java index a87e9ee5a2ced..71119e1170b05 100644 --- a/telephony/java/android/telephony/mbms/StreamingService.java +++ b/telephony/java/android/telephony/mbms/StreamingService.java @@ -28,7 +28,7 @@ import java.lang.annotation.RetentionPolicy; /** * Class used to represent a single MBMS stream. After a stream has been started with * {@link android.telephony.MbmsStreamingManager#startStreaming(StreamingServiceInfo, - * StreamingServiceCallback)}, + * StreamingServiceCallback, android.os.Handler)}, * this class is used to hold information about the stream and control it. * @hide */ @@ -36,7 +36,7 @@ public class StreamingService { private static final String LOG_TAG = "MbmsStreamingService"; /** - * The state of a stream, reported via {@link StreamingServiceCallback#streamStateUpdated} + * The state of a stream, reported via {@link StreamingServiceCallback#onStreamStateUpdated} * @hide */ @Retention(RetentionPolicy.SOURCE) @@ -48,7 +48,7 @@ public class StreamingService { /** * The reason for a stream state change, reported via - * {@link StreamingServiceCallback#streamStateUpdated} + * {@link StreamingServiceCallback#onStreamStateUpdated} * @hide */ @Retention(RetentionPolicy.SOURCE) @@ -65,7 +65,7 @@ public class StreamingService { /** * State changed due to a call to {@link #stopStreaming()} or * {@link android.telephony.MbmsStreamingManager#startStreaming(StreamingServiceInfo, - * StreamingServiceCallback)} + * StreamingServiceCallback, android.os.Handler)} */ public static final int REASON_BY_USER_REQUEST = 1; @@ -96,23 +96,24 @@ public class StreamingService { /** * The method of transmission currently used for a stream, - * reported via {@link StreamingServiceCallback#streamMethodUpdated} + * reported via {@link StreamingServiceCallback#onStreamMethodUpdated} */ public final static int BROADCAST_METHOD = 1; public final static int UNICAST_METHOD = 2; private final int mSubscriptionId; private final StreamingServiceInfo mServiceInfo; - private final IStreamingServiceCallback mCallback; + private final InternalStreamingServiceCallback mCallback; private IMbmsStreamingService mService; + /** * @hide */ public StreamingService(int subscriptionId, IMbmsStreamingService service, StreamingServiceInfo streamingServiceInfo, - IStreamingServiceCallback callback) { + InternalStreamingServiceCallback callback) { mSubscriptionId = subscriptionId; mService = service; mServiceInfo = streamingServiceInfo; diff --git a/telephony/java/android/telephony/mbms/StreamingServiceCallback.java b/telephony/java/android/telephony/mbms/StreamingServiceCallback.java index 9a62f2edcaf42..eeef8bcab04fa 100644 --- a/telephony/java/android/telephony/mbms/StreamingServiceCallback.java +++ b/telephony/java/android/telephony/mbms/StreamingServiceCallback.java @@ -16,14 +16,12 @@ package android.telephony.mbms; -import android.os.RemoteException; - /** * A callback class for use when the application is actively streaming content. The middleware * will provide updates on the status of the stream via this callback. * @hide */ -public class StreamingServiceCallback extends IStreamingServiceCallback.Stub { +public class StreamingServiceCallback { /** * Indicates broadcast signal strength is not available for this service. @@ -40,8 +38,7 @@ public class StreamingServiceCallback extends IStreamingServiceCallback.Stub { * @param errorCode The error code. * @param message A human-readable message generated by the middleware for debugging purposes. */ - @Override - public void error(int errorCode, String message) throws RemoteException { + public void onError(int errorCode, String message) { // default implementation empty } @@ -51,9 +48,8 @@ public class StreamingServiceCallback extends IStreamingServiceCallback.Stub { * See {@link StreamingService#STATE_STOPPED}, {@link StreamingService#STATE_STARTED} * and {@link StreamingService#STATE_STALLED}. */ - @Override - public void streamStateUpdated(@StreamingService.StreamingState int state, - @StreamingService.StreamingStateChangeReason int reason) throws RemoteException { + public void onStreamStateUpdated(@StreamingService.StreamingState int state, + @StreamingService.StreamingStateChangeReason int reason) { // default implementation empty } @@ -67,8 +63,7 @@ public class StreamingServiceCallback extends IStreamingServiceCallback.Stub { * This may be called when a looping stream hits the end or * when parameters have changed to account for time drift. */ - @Override - public void mediaDescriptionUpdated() throws RemoteException { + public void onMediaDescriptionUpdated() { // default implementation empty } @@ -82,8 +77,7 @@ public class StreamingServiceCallback extends IStreamingServiceCallback.Stub { * {@link #SIGNAL_STRENGTH_UNAVAILABLE} if broadcast is not available * for this service due to timing, geography or popularity. */ - @Override - public void broadcastSignalStrengthUpdated(int signalStrength) throws RemoteException { + public void onBroadcastSignalStrengthUpdated(int signalStrength) { // default implementation empty } @@ -103,8 +97,7 @@ public class StreamingServiceCallback extends IStreamingServiceCallback.Stub { * See {@link StreamingService#BROADCAST_METHOD} and * {@link StreamingService#UNICAST_METHOD} */ - @Override - public void streamMethodUpdated(int methodType) throws RemoteException { + public void onStreamMethodUpdated(int methodType) { // default implementation empty } } diff --git a/telephony/java/android/telephony/mbms/StreamingServiceInfo.java b/telephony/java/android/telephony/mbms/StreamingServiceInfo.java index 0d6c95c1eb014..8e7917a6992ec 100644 --- a/telephony/java/android/telephony/mbms/StreamingServiceInfo.java +++ b/telephony/java/android/telephony/mbms/StreamingServiceInfo.java @@ -29,7 +29,7 @@ import java.util.Map; * Describes a single MBMS streaming service. * @hide */ -public class StreamingServiceInfo extends ServiceInfo implements Parcelable { +public final class StreamingServiceInfo extends ServiceInfo implements Parcelable { /** * @param names User displayable names listed by language. diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java index ab1c982fa6f8e..802a949dae9e8 100644 --- a/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java +++ b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java @@ -19,6 +19,7 @@ package android.telephony.mbms.vendor; import android.annotation.Nullable; import android.annotation.SystemApi; import android.net.Uri; +import android.os.Binder; import android.os.RemoteException; import android.telephony.mbms.IMbmsStreamingManagerCallback; import android.telephony.mbms.IStreamingServiceCallback; @@ -59,23 +60,42 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub { * @hide */ @Override - public final int initialize(IMbmsStreamingManagerCallback listener, int subscriptionId) + public final int initialize(IMbmsStreamingManagerCallback listener, final int subscriptionId) throws RemoteException { + final int uid = Binder.getCallingUid(); + listener.asBinder().linkToDeath(new DeathRecipient() { + @Override + public void binderDied() { + onAppCallbackDied(uid, subscriptionId); + } + }, 0); + return initialize(new MbmsStreamingManagerCallback() { @Override - public void error(int errorCode, String message) throws RemoteException { - listener.error(errorCode, message); + public void onError(int errorCode, String message) { + try { + listener.error(errorCode, message); + } catch (RemoteException e) { + onAppCallbackDied(uid, subscriptionId); + } } @Override - public void streamingServicesUpdated(List services) throws - RemoteException { - listener.streamingServicesUpdated(services); + public void onStreamingServicesUpdated(List services) { + try { + listener.streamingServicesUpdated(services); + } catch (RemoteException e) { + onAppCallbackDied(uid, subscriptionId); + } } @Override - public void middlewareReady() throws RemoteException { - listener.middlewareReady(); + public void onMiddlewareReady() { + try { + listener.middlewareReady(); + } catch (RemoteException e) { + onAppCallbackDied(uid, subscriptionId); + } } }, subscriptionId); } @@ -129,32 +149,59 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub { @Override public int startStreaming(int subscriptionId, String serviceId, IStreamingServiceCallback listener) throws RemoteException { + final int uid = Binder.getCallingUid(); + listener.asBinder().linkToDeath(new DeathRecipient() { + @Override + public void binderDied() { + onAppCallbackDied(uid, subscriptionId); + } + }, 0); + return startStreaming(subscriptionId, serviceId, new StreamingServiceCallback() { @Override - public void error(int errorCode, String message) throws RemoteException { - listener.error(errorCode, message); + public void onError(int errorCode, String message) { + try { + listener.error(errorCode, message); + } catch (RemoteException e) { + onAppCallbackDied(uid, subscriptionId); + } } @Override - public void streamStateUpdated(@StreamingService.StreamingState int state, - @StreamingService.StreamingStateChangeReason int reason) - throws RemoteException { - listener.streamStateUpdated(state, reason); + public void onStreamStateUpdated(@StreamingService.StreamingState int state, + @StreamingService.StreamingStateChangeReason int reason) { + try { + listener.streamStateUpdated(state, reason); + } catch (RemoteException e) { + onAppCallbackDied(uid, subscriptionId); + } } @Override - public void mediaDescriptionUpdated() throws RemoteException { - listener.mediaDescriptionUpdated(); + public void onMediaDescriptionUpdated() { + try { + listener.mediaDescriptionUpdated(); + } catch (RemoteException e) { + onAppCallbackDied(uid, subscriptionId); + } } @Override - public void broadcastSignalStrengthUpdated(int signalStrength) throws RemoteException { - listener.broadcastSignalStrengthUpdated(signalStrength); + public void onBroadcastSignalStrengthUpdated(int signalStrength) { + try { + listener.broadcastSignalStrengthUpdated(signalStrength); + } catch (RemoteException e) { + onAppCallbackDied(uid, subscriptionId); + } } @Override - public void streamMethodUpdated(int methodType) throws RemoteException { - listener.streamMethodUpdated(methodType); + public void onStreamMethodUpdated(int methodType) { + try { + listener.streamMethodUpdated(methodType); + } catch (RemoteException e) { + onAppCallbackDied(uid, subscriptionId); + } } }); } @@ -221,4 +268,12 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub { @Override public void dispose(int subscriptionId) throws RemoteException { } + + /** + * Indicates that the app identified by the given UID and subscription ID has died. + * @param uid the UID of the app, as returned by {@link Binder#getCallingUid()}. + * @param subscriptionId The subscription ID the app is using. + */ + public void onAppCallbackDied(int uid, int subscriptionId) { + } } From 0bd7a6058c7b8570e9ec4050cf818603685e41b5 Mon Sep 17 00:00:00 2001 From: Hall Liu Date: Thu, 20 Jul 2017 15:32:51 -0700 Subject: [PATCH 3/4] Embms API adjustments for 7/21 * Enforce that only one instance of each manager can be active. * Add a death receipient for both managers to notify the app of binder death * Add documentation informing the app that it may not call create() multiple times * Fix a collision in streaming state reason codes * Add documentation in DownloadRequest to indicate which methods should be called by the middleware. Bug: 30981736 Test: testapps Change-Id: Ie15283b5c34fee736e8023dbd4f889c2ca95299e --- .../telephony/MbmsDownloadManager.java | 71 ++++++++++++--- .../telephony/MbmsStreamingManager.java | 90 ++++++++++++++----- .../telephony/mbms/DownloadRequest.java | 66 +++++++++++++- .../mbms/MbmsDownloadManagerCallback.java | 16 ++-- .../mbms/MbmsStreamingManagerCallback.java | 1 + .../telephony/mbms/StreamingService.java | 2 +- .../mbms/vendor/MbmsDownloadServiceBase.java | 34 ++++++- .../mbms/vendor/MbmsStreamingServiceBase.java | 2 +- 8 files changed, 233 insertions(+), 49 deletions(-) diff --git a/telephony/java/android/telephony/MbmsDownloadManager.java b/telephony/java/android/telephony/MbmsDownloadManager.java index 4c3f7e7ab5a8d..be193c65ed129 100644 --- a/telephony/java/android/telephony/MbmsDownloadManager.java +++ b/telephony/java/android/telephony/MbmsDownloadManager.java @@ -30,7 +30,6 @@ import android.os.RemoteException; import android.telephony.mbms.FileInfo; import android.telephony.mbms.DownloadRequest; import android.telephony.mbms.IDownloadProgressListener; -import android.telephony.mbms.IMbmsDownloadManagerCallback; import android.telephony.mbms.MbmsDownloadManagerCallback; import android.telephony.mbms.MbmsDownloadReceiver; import android.telephony.mbms.MbmsException; @@ -44,6 +43,7 @@ import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; @@ -207,8 +207,16 @@ public class MbmsDownloadManager { public static final int STATUS_PENDING_REPAIR = 3; public static final int STATUS_PENDING_DOWNLOAD_WINDOW = 4; + private static AtomicBoolean sIsInitialized = new AtomicBoolean(false); + private final Context mContext; private int mSubscriptionId = INVALID_SUBSCRIPTION_ID; + private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() { + @Override + public void binderDied() { + sendErrorToApp(MbmsException.ERROR_MIDDLEWARE_LOST, "Received death notification"); + } + }; private AtomicReference mService = new AtomicReference<>(null); private final MbmsDownloadManagerCallback mCallback; @@ -236,10 +244,21 @@ public class MbmsDownloadManager { * * Note that this call will bind a remote service and that may take a bit. The instance of * {@link MbmsDownloadManager} that is returned will not be ready for use until - * {@link IMbmsDownloadManagerCallback#middlewareReady()} is called on the provided callback. + * {@link MbmsDownloadManagerCallback#middlewareReady()} is called on the provided callback. * If you attempt to use the manager before it is ready, a {@link MbmsException} will be thrown. * - * This also may throw an {@link IllegalArgumentException} or a {@link MbmsException}. + * This also may throw an {@link IllegalArgumentException} or an {@link IllegalStateException}. + * + * You may only have one instance of {@link MbmsDownloadManager} per UID. If you call this + * method while there is an active instance of {@link MbmsDownloadManager} in your process + * (in other words, one that has not had {@link #dispose()} called on it), this method will + * throw an {@link MbmsException}. If you call this method in a different process + * running under the same UID, an error will be indicated via + * {@link MbmsDownloadManagerCallback#error(int, String)}. + * + * Note that initialization may fail asynchronously. If you wish to try again after you + * receive such an asynchronous error, you must call dispose() on the instance of + * {@link MbmsDownloadManager} that you received before calling this method again. * * @param context The instance of {@link Context} to use * @param listener A callback to get asynchronous error messages and file service updates. @@ -249,8 +268,16 @@ public class MbmsDownloadManager { public static MbmsDownloadManager create(Context context, MbmsDownloadManagerCallback listener, int subscriptionId) throws MbmsException { + if (!sIsInitialized.compareAndSet(false, true)) { + throw new MbmsException(MbmsException.InitializationErrors.ERROR_DUPLICATE_INITIALIZE); + } MbmsDownloadManager mdm = new MbmsDownloadManager(context, listener, subscriptionId); - mdm.bindAndInitialize(); + try { + mdm.bindAndInitialize(); + } catch (MbmsException e) { + sIsInitialized.set(false); + throw e; + } return mdm; } @@ -266,16 +293,27 @@ public class MbmsDownloadManager { result = downloadService.initialize(mSubscriptionId, mCallback); } catch (RemoteException e) { Log.e(LOG_TAG, "Service died before initialization"); + sIsInitialized.set(false); return; } catch (RuntimeException e) { Log.e(LOG_TAG, "Runtime exception during initialization"); - mCallback.error( + sendErrorToApp( MbmsException.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE, e.toString()); + sIsInitialized.set(false); return; } if (result != MbmsException.SUCCESS) { - mCallback.error(result, "Error returned during initialization"); + sendErrorToApp(result, "Error returned during initialization"); + sIsInitialized.set(false); + return; + } + try { + downloadService.asBinder().linkToDeath(mDeathRecipient, 0); + } catch (RemoteException e) { + sendErrorToApp(MbmsException.ERROR_MIDDLEWARE_LOST, + "Middleware lost during initialization"); + sIsInitialized.set(false); return; } mService.set(downloadService); @@ -283,6 +321,7 @@ public class MbmsDownloadManager { @Override public void onServiceDisconnected(ComponentName name) { + sIsInitialized.set(false); mService.set(null); } }); @@ -292,7 +331,7 @@ public class MbmsDownloadManager { * An inspection API to retrieve the list of available * {@link android.telephony.mbms.FileServiceInfo}s currently being advertised. * The results are returned asynchronously via a call to - * {@link IMbmsDownloadManagerCallback#fileServicesUpdated(List)} + * {@link MbmsDownloadManagerCallback#fileServicesUpdated(List)} * * The serviceClasses argument lets the app filter on types of programming and is opaque data * negotiated beforehand between the app and the carrier. @@ -306,7 +345,7 @@ public class MbmsDownloadManager { * {@link MbmsException.StreamingErrors#ERROR_UNABLE_TO_START_SERVICE} * * @param classList A list of service classes which the app wishes to receive - * {@link IMbmsDownloadManagerCallback#fileServicesUpdated(List)} callbacks + * {@link MbmsDownloadManagerCallback#fileServicesUpdated(List)} callbacks * about. Subsequent calls to this method will replace this list of service * classes (i.e. the middleware will no longer send updates for services * matching classes only in the old list). @@ -336,7 +375,7 @@ public class MbmsDownloadManager { * local instance of {@link android.content.SharedPreferences} and by the middleware. * * If this method is not called at least once before calling - * {@link #download(DownloadRequest, IDownloadCallback)}, the framework + * {@link #download(DownloadRequest, IDownloadProgressListener)}, the framework * will default to a directory formed by the concatenation of the app's files directory and * {@link android.telephony.mbms.MbmsTempFileProvider#DEFAULT_TOP_LEVEL_TEMP_DIRECTORY}. * @@ -434,7 +473,7 @@ public class MbmsDownloadManager { /** * Returns a list of pending {@link DownloadRequest}s that originated from this application. * A pending request is one that was issued via - * {@link #download(DownloadRequest, IDownloadCallback)} but not cancelled through + * {@link #download(DownloadRequest, IDownloadProgressListener)} but not cancelled through * {@link #cancelDownload(DownloadRequest)}. * @return A list, possibly empty, of {@link DownloadRequest}s */ @@ -550,10 +589,12 @@ public class MbmsDownloadManager { return; } downloadService.dispose(mSubscriptionId); - mService.set(null); } catch (RemoteException e) { // Ignore Log.i(LOG_TAG, "Remote exception while disposing of service"); + } finally { + mService.set(null); + sIsInitialized.set(false); } } @@ -651,4 +692,12 @@ public class MbmsDownloadManager { } } } + + private void sendErrorToApp(int errorCode, String message) { + try { + mCallback.error(errorCode, message); + } catch (RemoteException e) { + // Ignore, should not happen locally. + } + } } diff --git a/telephony/java/android/telephony/MbmsStreamingManager.java b/telephony/java/android/telephony/MbmsStreamingManager.java index 2fe1c6cc2e657..7a6631a3d90c9 100644 --- a/telephony/java/android/telephony/MbmsStreamingManager.java +++ b/telephony/java/android/telephony/MbmsStreamingManager.java @@ -37,6 +37,7 @@ import android.telephony.mbms.vendor.IMbmsStreamingService; import android.util.Log; import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; @@ -58,7 +59,17 @@ public class MbmsStreamingManager { public static final String MBMS_STREAMING_SERVICE_ACTION = "android.telephony.action.EmbmsStreaming"; + private static AtomicBoolean sIsInitialized = new AtomicBoolean(false); + private AtomicReference mService = new AtomicReference<>(null); + private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() { + @Override + public void binderDied() { + sIsInitialized.set(false); + sendErrorToApp(MbmsException.ERROR_MIDDLEWARE_LOST, "Received death notification"); + } + }; + private InternalStreamingManagerCallback mInternalCallback; private final Context mContext; @@ -82,6 +93,18 @@ public class MbmsStreamingManager { * main thread. This may throw an {@link MbmsException}, indicating errors that may happen * during the initialization or binding process. * + * + * You may only have one instance of {@link MbmsStreamingManager} per UID. If you call this + * method while there is an active instance of {@link MbmsStreamingManager} in your process + * (in other words, one that has not had {@link #dispose()} called on it), this method will + * throw an {@link MbmsException}. If you call this method in a different process + * running under the same UID, an error will be indicated via + * {@link MbmsStreamingManagerCallback#onError(int, String)}. + * + * Note that initialization may fail asynchronously. If you wish to try again after you + * receive such an asynchronous error, you must call dispose() on the instance of + * {@link MbmsStreamingManager} that you received before calling this method again. + * * @param context The {@link Context} to use. * @param callback A callback object on which you wish to receive results of asynchronous * operations. @@ -93,9 +116,17 @@ public class MbmsStreamingManager { public static MbmsStreamingManager create(Context context, MbmsStreamingManagerCallback callback, int subscriptionId, Handler handler) throws MbmsException { + if (!sIsInitialized.compareAndSet(false, true)) { + throw new MbmsException(MbmsException.InitializationErrors.ERROR_DUPLICATE_INITIALIZE); + } MbmsStreamingManager manager = new MbmsStreamingManager(context, callback, subscriptionId, handler); - manager.bindAndInitialize(); + try { + manager.bindAndInitialize(); + } catch (MbmsException e) { + sIsInitialized.set(false); + throw e; + } return manager; } @@ -127,17 +158,19 @@ public class MbmsStreamingManager { * May throw an {@link IllegalStateException} */ public void dispose() { - IMbmsStreamingService streamingService = mService.get(); - if (streamingService == null) { - // Ignore and return, assume already disposed. - return; - } try { + IMbmsStreamingService streamingService = mService.get(); + if (streamingService == null) { + // Ignore and return, assume already disposed. + return; + } streamingService.dispose(mSubscriptionId); } catch (RemoteException e) { // Ignore for now + } finally { + mService.set(null); + sIsInitialized.set(false); } - mService.set(null); } /** @@ -171,6 +204,7 @@ public class MbmsStreamingManager { } catch (RemoteException e) { Log.w(LOG_TAG, "Remote process died"); mService.set(null); + sIsInitialized.set(false); throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST); } } @@ -223,6 +257,7 @@ public class MbmsStreamingManager { } catch (RemoteException e) { Log.w(LOG_TAG, "Remote process died"); mService.set(null); + sIsInitialized.set(false); throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST); } @@ -242,26 +277,30 @@ public class MbmsStreamingManager { mSubscriptionId); } catch (RemoteException e) { Log.e(LOG_TAG, "Service died before initialization"); + sendErrorToApp( + MbmsException.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE, + e.toString()); + sIsInitialized.set(false); return; } catch (RuntimeException e) { Log.e(LOG_TAG, "Runtime exception during initialization"); - try { - mInternalCallback.error( - MbmsException.InitializationErrors - .ERROR_UNABLE_TO_INITIALIZE, - e.toString()); - } catch (RemoteException e1) { - // ignore - } + sendErrorToApp( + MbmsException.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE, + e.toString()); + sIsInitialized.set(false); return; } if (result != MbmsException.SUCCESS) { - try { - mInternalCallback.error( - result, "Error returned during initialization"); - } catch (RemoteException e) { - // ignore - } + sendErrorToApp(result, "Error returned during initialization"); + sIsInitialized.set(false); + return; + } + try { + streamingService.asBinder().linkToDeath(mDeathRecipient, 0); + } catch (RemoteException e) { + sendErrorToApp(MbmsException.ERROR_MIDDLEWARE_LOST, + "Middleware lost during initialization"); + sIsInitialized.set(false); return; } mService.set(streamingService); @@ -269,8 +308,17 @@ public class MbmsStreamingManager { @Override public void onServiceDisconnected(ComponentName name) { + sIsInitialized.set(false); mService.set(null); } }); } + + private void sendErrorToApp(int errorCode, String message) { + try { + mInternalCallback.error(errorCode, message); + } catch (RemoteException e) { + // Ignore, should not happen locally. + } + } } diff --git a/telephony/java/android/telephony/mbms/DownloadRequest.java b/telephony/java/android/telephony/mbms/DownloadRequest.java index 01e0bbdfc0a0a..eae9011e42c8a 100644 --- a/telephony/java/android/telephony/mbms/DownloadRequest.java +++ b/telephony/java/android/telephony/mbms/DownloadRequest.java @@ -25,6 +25,7 @@ import android.util.Log; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.File; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; @@ -77,12 +78,18 @@ public class DownloadRequest implements Parcelable { private String appIntent; private int version = CURRENT_VERSION; + /** + * Sets the service from which the download request to be built will download from. + * @param serviceInfo + * @return + */ public Builder setServiceInfo(FileServiceInfo serviceInfo) { fileServiceId = serviceInfo.getServiceId(); return this; } /** + * Set the service ID for the download request. For use by the middleware only. * @hide * TODO: systemapi */ @@ -91,11 +98,23 @@ public class DownloadRequest implements Parcelable { return this; } + /** + * Sets the source URI for the download request to be built. + * @param source + * @return + */ public Builder setSource(Uri source) { this.source = source; return this; } + /** + * Sets the destination URI for the download request to be built. The middleware should + * not set this directly. + * @param dest A URI obtained from {@link Uri#fromFile(File)}, denoting the requested + * final destination of the download. + * @return + */ public Builder setDest(Uri dest) { if (dest.toString().length() > MAX_DESTINATION_URI_SIZE) { throw new IllegalArgumentException("Destination uri must not exceed length " + @@ -105,11 +124,25 @@ public class DownloadRequest implements Parcelable { return this; } - public Builder setSubscriptionId(int sub) { - this.subscriptionId = sub; + /** + * Set the subscription ID on which the file(s) should be downloaded. + * @param subscriptionId + * @return + */ + public Builder setSubscriptionId(int subscriptionId) { + this.subscriptionId = subscriptionId; return this; } + /** + * Set the {@link Intent} that should be sent when the download completes or fails. This + * should be an intent with a explicit {@link android.content.ComponentName} targeted to a + * {@link android.content.BroadcastReceiver} in the app's package. + * + * The middleware should not use this method. + * @param intent + * @return + */ public Builder setAppIntent(Intent intent) { this.appIntent = intent.toUri(0); if (this.appIntent.length() > MAX_APP_INTENT_SIZE) { @@ -120,7 +153,12 @@ public class DownloadRequest implements Parcelable { } /** - * For use by middleware only + * For use by the middleware to set the byte array of opaque data. The opaque data + * includes information about the download request that is used by the client app and the + * manager code, but is irrelevant to the middleware. + * @param data A byte array, the contents of which should have been originally obtained + * from {@link DownloadRequest#getOpaqueData()}. + * @return * TODO: systemapi * @hide */ @@ -201,22 +239,40 @@ public class DownloadRequest implements Parcelable { out.writeInt(version); } + /** + * @return The ID of the file service to download from. + */ public String getFileServiceId() { return fileServiceId; } + /** + * @return The source URI to download from + */ public Uri getSourceUri() { return sourceUri; } + /** + * For use by the client app only. + * @return The URI of the final destination of the download. + */ public Uri getDestinationUri() { return destinationUri; } + /** + * @return The subscription ID on which to perform MBMS operations. + */ public int getSubscriptionId() { return subscriptionId; } + /** + * For internal use -- returns the intent to send to the app after download completion or + * failure. + * @hide + */ public Intent getIntentForApp() { try { return Intent.parseUri(serializedResultIntentForApp, 0); @@ -226,6 +282,10 @@ public class DownloadRequest implements Parcelable { } /** + * For use by the middleware only. The byte array returned from this method should be + * persisted and sent back to the app upon download completion or failure by passing it into + * {@link Builder#setOpaqueData(byte[])}. + * @return A byte array of opaque data to persist. * @hide * TODO: systemapi */ diff --git a/telephony/java/android/telephony/mbms/MbmsDownloadManagerCallback.java b/telephony/java/android/telephony/mbms/MbmsDownloadManagerCallback.java index ba25f663ffb44..17291d09215df 100644 --- a/telephony/java/android/telephony/mbms/MbmsDownloadManagerCallback.java +++ b/telephony/java/android/telephony/mbms/MbmsDownloadManagerCallback.java @@ -16,6 +16,9 @@ package android.telephony.mbms; +import android.os.RemoteException; +import android.telephony.MbmsDownloadManager; + import java.util.List; /** @@ -24,12 +27,8 @@ import java.util.List; */ public class MbmsDownloadManagerCallback extends IMbmsDownloadManagerCallback.Stub { - public final static int ERROR_CARRIER_NOT_SUPPORTED = 1; - public final static int ERROR_UNABLE_TO_INITIALIZE = 2; - public final static int ERROR_UNABLE_TO_ALLOCATE_MEMORY = 3; - - - public void error(int errorCode, String message) { + @Override + public void error(int errorCode, String message) throws RemoteException { // default implementation empty } @@ -45,7 +44,8 @@ public class MbmsDownloadManagerCallback extends IMbmsDownloadManagerCallback.St * @param services a List of FileServiceInfos * */ - public void fileServicesUpdated(List services) { + @Override + public void fileServicesUpdated(List services) throws RemoteException { // default implementation empty } @@ -58,7 +58,7 @@ public class MbmsDownloadManagerCallback extends IMbmsDownloadManagerCallback.St * or {@link MbmsException.GeneralErrors#ERROR_MIDDLEWARE_NOT_YET_READY} */ @Override - public void middlewareReady() { + public void middlewareReady() throws RemoteException { // default implementation empty } } diff --git a/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java b/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java index b6b007bcaf5b7..831050efdd477 100644 --- a/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java +++ b/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java @@ -18,6 +18,7 @@ package android.telephony.mbms; import android.content.Context; import android.os.RemoteException; +import android.telephony.MbmsStreamingManager; import java.util.List; diff --git a/telephony/java/android/telephony/mbms/StreamingService.java b/telephony/java/android/telephony/mbms/StreamingService.java index 71119e1170b05..5c4b7862289f7 100644 --- a/telephony/java/android/telephony/mbms/StreamingService.java +++ b/telephony/java/android/telephony/mbms/StreamingService.java @@ -92,7 +92,7 @@ public class StreamingService { /** * State changed due to the device leaving the where this stream is being broadcast. */ - public static final int REASON_LEFT_MBMS_BROADCAST_AREA = 5; + public static final int REASON_LEFT_MBMS_BROADCAST_AREA = 6; /** * The method of transmission currently used for a stream, diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java index edd585808580f..a0834eb6864fa 100644 --- a/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java +++ b/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java @@ -20,8 +20,10 @@ import android.annotation.NonNull; import android.os.RemoteException; import android.telephony.mbms.DownloadRequest; import android.telephony.mbms.FileInfo; +import android.telephony.mbms.FileServiceInfo; import android.telephony.mbms.IDownloadProgressListener; import android.telephony.mbms.IMbmsDownloadManagerCallback; +import android.telephony.mbms.MbmsDownloadManagerCallback; import android.telephony.mbms.MbmsException; import java.util.List; @@ -44,13 +46,37 @@ public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub { * or {@link MbmsException#SUCCESS}. Non-successful error codes will be passed to the app via * {@link IMbmsDownloadManagerCallback#error(int, String)}. * - * @param listener The callback to use to communicate with the app. + * @param callback The callback to use to communicate with the app. * @param subscriptionId The subscription ID to use. */ + public int initialize(int subscriptionId, MbmsDownloadManagerCallback callback) + throws RemoteException { + return 0; + } + + /** + * Actual AIDL implementation -- hides the callback AIDL from the API. + * @hide + */ @Override public int initialize(int subscriptionId, - IMbmsDownloadManagerCallback listener) throws RemoteException { - return 0; + IMbmsDownloadManagerCallback callback) throws RemoteException { + return initialize(subscriptionId, new MbmsDownloadManagerCallback() { + @Override + public void error(int errorCode, String message) throws RemoteException { + callback.error(errorCode, message); + } + + @Override + public void fileServicesUpdated(List services) throws RemoteException { + callback.fileServicesUpdated(services); + } + + @Override + public void middlewareReady() throws RemoteException { + callback.middlewareReady(); + } + }); } /** @@ -119,7 +145,7 @@ public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub { /** * Returns a list of pending {@link DownloadRequest}s that originated from the calling * application, identified by its uid. A pending request is one that was issued via - * {@link #download(DownloadRequest, IDownloadCallback)} but not cancelled through + * {@link #download(DownloadRequest, IDownloadProgressListener)} but not cancelled through * {@link #cancelDownload(DownloadRequest)}. * The middleware must return a non-null result synchronously or throw an exception * inheriting from {@link RuntimeException}. diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java index 802a949dae9e8..0579d7e1ea9e9 100644 --- a/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java +++ b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java @@ -39,7 +39,7 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub { /** * Initialize streaming service for this app and subId, registering the listener. * - * May throw an {@link IllegalArgumentException} or an {@link IllegalStateException}, which + * May throw an {@link IllegalArgumentException} or a {@link SecurityException}, which * will be intercepted and passed to the app as * {@link android.telephony.mbms.MbmsException.InitializationErrors#ERROR_UNABLE_TO_INITIALIZE} * From 25bdb2c8cce88e6abc31db851da48bcd917eaaf6 Mon Sep 17 00:00:00 2001 From: Hall Liu Date: Thu, 27 Jul 2017 15:33:31 -0700 Subject: [PATCH 4/4] Embms adjustments for 7/28 * Move some vendor intents and extras into a VendorIntents class * Add a download result RESULT_IO_ERROR * Add documentation noting that repeated calls to setTempFileRootDirectory will not throw an error if the parameter is the same. * Add getTempFileRootDirectory method for app * Hide AIDL classes from the public/system API surfaces for download * Remove size and md5hash from FileInfo Test: testapps Bug: 30981736 Change-Id: I8c968a7d68db2588ee550167ed2693fe89c5925a --- .../telephony/MbmsDownloadManager.java | 185 ++++-------------- .../mbms/DownloadProgressListener.java | 5 +- .../java/android/telephony/mbms/FileInfo.java | 29 +-- .../telephony/mbms/MbmsDownloadReceiver.java | 63 +++--- .../mbms/vendor/MbmsDownloadServiceBase.java | 28 ++- .../mbms/vendor/MbmsStreamingServiceBase.java | 34 ++-- .../telephony/mbms/vendor/VendorIntents.java | 166 ++++++++++++++++ 7 files changed, 277 insertions(+), 233 deletions(-) create mode 100644 telephony/java/android/telephony/mbms/vendor/VendorIntents.java diff --git a/telephony/java/android/telephony/MbmsDownloadManager.java b/telephony/java/android/telephony/MbmsDownloadManager.java index be193c65ed129..1e8cf185d4e4c 100644 --- a/telephony/java/android/telephony/MbmsDownloadManager.java +++ b/telephony/java/android/telephony/MbmsDownloadManager.java @@ -18,18 +18,19 @@ package android.telephony; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SdkConstant; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.content.SharedPreferences; -import android.content.pm.ResolveInfo; import android.net.Uri; import android.os.IBinder; import android.os.RemoteException; +import android.telephony.mbms.DownloadProgressListener; import android.telephony.mbms.FileInfo; import android.telephony.mbms.DownloadRequest; -import android.telephony.mbms.IDownloadProgressListener; import android.telephony.mbms.MbmsDownloadManagerCallback; import android.telephony.mbms.MbmsDownloadReceiver; import android.telephony.mbms.MbmsException; @@ -52,147 +53,38 @@ import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; public class MbmsDownloadManager { private static final String LOG_TAG = MbmsDownloadManager.class.getSimpleName(); + /** @hide */ + // TODO: systemapi + @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION) public static final String MBMS_DOWNLOAD_SERVICE_ACTION = "android.telephony.action.EmbmsDownload"; - /** - * The MBMS middleware should send this when a download of single file has completed or - * failed. Mandatory extras are - * {@link #EXTRA_RESULT} - * {@link #EXTRA_FILE_INFO} - * {@link #EXTRA_REQUEST} - * {@link #EXTRA_TEMP_LIST} - * {@link #EXTRA_FINAL_URI} - * - * TODO: future systemapi - */ - public static final String ACTION_DOWNLOAD_RESULT_INTERNAL = - "android.telephony.mbms.action.DOWNLOAD_RESULT_INTERNAL"; - - /** - * The MBMS middleware should send this when it wishes to request {@code content://} URIs to - * serve as temp files for downloads or when it wishes to resume paused downloads. Mandatory - * extras are - * {@link #EXTRA_REQUEST} - * - * Optional extras are - * {@link #EXTRA_FD_COUNT} (0 if not present) - * {@link #EXTRA_PAUSED_LIST} (empty if not present) - * - * TODO: future systemapi - */ - public static final String ACTION_FILE_DESCRIPTOR_REQUEST = - "android.telephony.mbms.action.FILE_DESCRIPTOR_REQUEST"; - - /** - * The MBMS middleware should send this when it wishes to clean up temp files in the app's - * filesystem. Mandatory extras are: - * {@link #EXTRA_TEMP_FILES_IN_USE} - * - * TODO: future systemapi - */ - public static final String ACTION_CLEANUP = - "android.telephony.mbms.action.CLEANUP"; /** * Integer extra indicating the result code of the download. One of * {@link #RESULT_SUCCESSFUL}, {@link #RESULT_EXPIRED}, or {@link #RESULT_CANCELLED}. - * TODO: Not systemapi. */ public static final String EXTRA_RESULT = "android.telephony.mbms.extra.RESULT"; /** * Extra containing the {@link android.telephony.mbms.FileInfo} for which the download result * is for. Must not be null. - * TODO: Not systemapi. */ public static final String EXTRA_FILE_INFO = "android.telephony.mbms.extra.FILE_INFO"; - /** - * Extra containing the {@link DownloadRequest} for which the download result or file - * descriptor request is for. Must not be null. - * TODO: future systemapi (here and and all extras) except the three for the app intent - */ - public static final String EXTRA_REQUEST = "android.telephony.mbms.extra.REQUEST"; - - /** - * Extra containing a {@link List} of {@link Uri}s that were used as temp files for this - * completed file. These {@link Uri}s should have scheme {@code file://}, and the temp - * files will be deleted upon receipt of the intent. - * May be null. - */ - public static final String EXTRA_TEMP_LIST = "android.telephony.mbms.extra.TEMP_LIST"; - - /** - * Extra containing a single {@link Uri} indicating the path to the temp file in which the - * decoded downloaded file resides. Must not be null. - */ - public static final String EXTRA_FINAL_URI = "android.telephony.mbms.extra.FINAL_URI"; - - /** - * Extra containing an integer indicating the number of temp files requested. - */ - public static final String EXTRA_FD_COUNT = "android.telephony.mbms.extra.FD_COUNT"; - - /** - * Extra containing a list of {@link Uri}s that the middleware is requesting access to via - * {@link #ACTION_FILE_DESCRIPTOR_REQUEST} in order to resume downloading. These {@link Uri}s - * should have scheme {@code file://}. - */ - public static final String EXTRA_PAUSED_LIST = "android.telephony.mbms.extra.PAUSED_LIST"; - - /** - * Extra containing a list of {@link android.telephony.mbms.UriPathPair}s, used in the - * response to {@link #ACTION_FILE_DESCRIPTOR_REQUEST}. These are temp files that are meant - * to be used for new file downloads. - */ - public static final String EXTRA_FREE_URI_LIST = "android.telephony.mbms.extra.FREE_URI_LIST"; - - /** - * Extra containing a list of {@link android.telephony.mbms.UriPathPair}s, used in the - * response to {@link #ACTION_FILE_DESCRIPTOR_REQUEST}. These - * {@link android.telephony.mbms.UriPathPair}s contain {@code content://} URIs that provide - * access to previously paused downloads. - */ - public static final String EXTRA_PAUSED_URI_LIST = - "android.telephony.mbms.extra.PAUSED_URI_LIST"; - - /** - * Extra containing a string that points to the middleware's knowledge of where the temp file - * root for the app is. The path should be a canonical path as returned by - * {@link File#getCanonicalPath()} - */ - public static final String EXTRA_TEMP_FILE_ROOT = - "android.telephony.mbms.extra.TEMP_FILE_ROOT"; - - /** - * Extra containing a list of {@link Uri}s indicating temp files which the middleware is - * still using. - */ - 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 * {@link android.telephony.mbms.DownloadRequest.Builder#setAppIntent(Intent)}. * Will always be set to a non-null value if {@link #EXTRA_RESULT} is set to * {@link #RESULT_SUCCESSFUL}. - * TODO: Not systemapi. */ public static final String EXTRA_COMPLETED_FILE_URI = "android.telephony.mbms.extra.COMPLETED_FILE_URI"; public static final int RESULT_SUCCESSFUL = 1; - public static final int RESULT_CANCELLED = 2; - public static final int RESULT_EXPIRED = 3; + public static final int RESULT_CANCELLED = 2; + public static final int RESULT_EXPIRED = 3; + public static final int RESULT_IO_ERROR = 4; // TODO - more results! /** @hide */ @@ -375,14 +267,15 @@ public class MbmsDownloadManager { * local instance of {@link android.content.SharedPreferences} and by the middleware. * * If this method is not called at least once before calling - * {@link #download(DownloadRequest, IDownloadProgressListener)}, the framework + * {@link #download(DownloadRequest, DownloadProgressListener)}, the framework * will default to a directory formed by the concatenation of the app's files directory and * {@link android.telephony.mbms.MbmsTempFileProvider#DEFAULT_TOP_LEVEL_TEMP_DIRECTORY}. * * Before calling this method, the app must cancel all of its pending * {@link DownloadRequest}s via {@link #cancelDownload(DownloadRequest)}. If this is not done, * an {@link MbmsException} will be thrown with code - * {@link MbmsException.DownloadErrors#ERROR_CANNOT_CHANGE_TEMP_FILE_ROOT} + * {@link MbmsException.DownloadErrors#ERROR_CANNOT_CHANGE_TEMP_FILE_ROOT} unless the + * provided directory is the same as what has been previously configured. * * The {@link File} supplied as a root temp file directory must already exist. If not, an * {@link IllegalArgumentException} will be thrown. @@ -422,6 +315,26 @@ public class MbmsDownloadManager { prefs.edit().putString(MbmsTempFileProvider.TEMP_FILE_ROOT_PREF_NAME, filePath).apply(); } + /** + * Retrieves the currently configured temp file root directory. Returns the file that was + * configured via {@link #setTempFileRootDirectory(File)} or the default directory + * {@link #download(DownloadRequest, DownloadProgressListener)} was called without ever setting + * the temp file root. If neither method has been called since the last time the app's shared + * preferences were reset, returns null. + * + * @return A {@link File} pointing to the configured temp file directory, or null if not yet + * configured. + */ + public @Nullable File getTempFileRootDirectory() { + SharedPreferences prefs = mContext.getSharedPreferences( + MbmsTempFileProvider.TEMP_FILE_ROOT_PREF_FILE_NAME, 0); + String path = prefs.getString(MbmsTempFileProvider.TEMP_FILE_ROOT_PREF_NAME, null); + if (path != null) { + return new File(path); + } + return null; + } + /** * Requests a download of a file that is available via multicast. * @@ -443,7 +356,7 @@ public class MbmsDownloadManager { * @param progressListener Optional listener that will be provided progress updates * if the app is running. */ - public void download(DownloadRequest request, IDownloadProgressListener progressListener) + public void download(DownloadRequest request, DownloadProgressListener progressListener) throws MbmsException { IMbmsDownloadService downloadService = mService.get(); if (downloadService == null) { @@ -473,7 +386,7 @@ public class MbmsDownloadManager { /** * Returns a list of pending {@link DownloadRequest}s that originated from this application. * A pending request is one that was issued via - * {@link #download(DownloadRequest, IDownloadProgressListener)} but not cancelled through + * {@link #download(DownloadRequest, DownloadProgressListener)} but not cancelled through * {@link #cancelDownload(DownloadRequest)}. * @return A list, possibly empty, of {@link DownloadRequest}s */ @@ -598,36 +511,6 @@ public class MbmsDownloadManager { } } - /** - * Retrieves the {@link ComponentName} for the {@link android.content.BroadcastReceiver} that - * the various intents from the middleware should be targeted towards. - * @param uid The uid of the frontend app. - * @return The component name of the receiver that the middleware should send its intents to, - * or null if the app didn't declare it in the manifest. - * - * @hide - * future systemapi - */ - public static ComponentName getAppReceiverFromUid(Context context, int uid) { - String[] packageNames = context.getPackageManager().getPackagesForUid(uid); - if (packageNames == null) { - return null; - } - - for (String packageName : packageNames) { - ComponentName candidate = new ComponentName(packageName, - MbmsDownloadReceiver.class.getCanonicalName()); - Intent queryIntent = new Intent(); - queryIntent.setComponent(candidate); - List receivers = - context.getPackageManager().queryBroadcastReceivers(queryIntent, 0); - if (receivers != null && receivers.size() > 0) { - return candidate; - } - } - return null; - } - private void writeDownloadRequestToken(DownloadRequest request) { File token = getDownloadRequestTokenPath(request); if (!token.getParentFile().exists()) { diff --git a/telephony/java/android/telephony/mbms/DownloadProgressListener.java b/telephony/java/android/telephony/mbms/DownloadProgressListener.java index d6bd5dca87819..d91e9ad24a9ac 100644 --- a/telephony/java/android/telephony/mbms/DownloadProgressListener.java +++ b/telephony/java/android/telephony/mbms/DownloadProgressListener.java @@ -16,6 +16,8 @@ package android.telephony.mbms; +import android.os.RemoteException; + /** * A optional listener class used by download clients to track progress. * @hide @@ -38,8 +40,9 @@ public class DownloadProgressListener extends IDownloadProgressListener.Stub { * @param currentDecodedSize is the number of bytes that have been decoded. * @param fullDecodedSize is the total number of bytes that make up the final decoded content. */ + @Override public void progress(DownloadRequest request, FileInfo fileInfo, int currentDownloadSize, int fullDownloadSize, - int currentDecodedSize, int fullDecodedSize) { + int currentDecodedSize, int fullDecodedSize) throws RemoteException { } } diff --git a/telephony/java/android/telephony/mbms/FileInfo.java b/telephony/java/android/telephony/mbms/FileInfo.java index b8e1c49f6b4a8..f97131dda4271 100644 --- a/telephony/java/android/telephony/mbms/FileInfo.java +++ b/telephony/java/android/telephony/mbms/FileInfo.java @@ -38,16 +38,6 @@ public class FileInfo implements Parcelable { */ private final String mimeType; - /** - * The size of the file in bytes. - */ - private final long size; - - /** - * The MD5 hash of the file. - */ - private final byte md5Hash[]; - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { @Override @@ -65,29 +55,20 @@ public class FileInfo implements Parcelable { * @hide * TODO: systemapi */ - public FileInfo(Uri uri, String mimeType, long size, byte[] md5Hash) { + public FileInfo(Uri uri, String mimeType) { this.uri = uri; this.mimeType = mimeType; - this.size = size; - this.md5Hash = md5Hash; } private FileInfo(Parcel in) { uri = in.readParcelable(null); mimeType = in.readString(); - size = in.readLong(); - int arraySize = in.readInt(); - md5Hash = new byte[arraySize]; - in.readByteArray(md5Hash); } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeParcelable(uri, flags); dest.writeString(mimeType); - dest.writeLong(size); - dest.writeInt(md5Hash.length); - dest.writeByteArray(md5Hash); } @Override @@ -102,12 +83,4 @@ public class FileInfo implements Parcelable { public String getMimeType() { return mimeType; } - - public long getSize() { - return size; - } - - public byte[] getMd5Hash() { - return md5Hash; - } } diff --git a/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java b/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java index 339ff3985bffc..ba7d120a3b7c8 100644 --- a/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java +++ b/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java @@ -25,6 +25,7 @@ import android.content.pm.PackageManager; import android.net.Uri; import android.os.Bundle; import android.telephony.MbmsDownloadManager; +import android.telephony.mbms.vendor.VendorIntents; import android.util.Log; import java.io.File; @@ -56,9 +57,9 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { /** * 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}. + * {@link VendorIntents#ACTION_DOWNLOAD_RESULT_INTERNAL}, + * {@link VendorIntents#ACTION_FILE_DESCRIPTOR_REQUEST}, or + * {@link VendorIntents#ACTION_CLEANUP}. * This is a fatal result code and no result extras should be expected. */ public static final int RESULT_INVALID_ACTION = 1; @@ -70,7 +71,7 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { public static final int RESULT_MALFORMED_INTENT = 2; /** - * Indicates that the supplied value for {@link MbmsDownloadManager#EXTRA_TEMP_FILE_ROOT} + * Indicates that the supplied value for {@link VendorIntents#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. */ @@ -104,18 +105,18 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { setResultCode(RESULT_MALFORMED_INTENT); return; } - if (!Objects.equals(intent.getStringExtra(MbmsDownloadManager.EXTRA_TEMP_FILE_ROOT), + if (!Objects.equals(intent.getStringExtra(VendorIntents.EXTRA_TEMP_FILE_ROOT), MbmsTempFileProvider.getEmbmsTempFileDir(context).getPath())) { setResultCode(RESULT_BAD_TEMP_FILE_ROOT); return; } - if (MbmsDownloadManager.ACTION_DOWNLOAD_RESULT_INTERNAL.equals(intent.getAction())) { + if (VendorIntents.ACTION_DOWNLOAD_RESULT_INTERNAL.equals(intent.getAction())) { moveDownloadedFile(context, intent); cleanupPostMove(context, intent); - } else if (MbmsDownloadManager.ACTION_FILE_DESCRIPTOR_REQUEST.equals(intent.getAction())) { + } else if (VendorIntents.ACTION_FILE_DESCRIPTOR_REQUEST.equals(intent.getAction())) { generateTempFiles(context, intent); - } else if (MbmsDownloadManager.ACTION_CLEANUP.equals(intent.getAction())) { + } else if (VendorIntents.ACTION_CLEANUP.equals(intent.getAction())) { cleanupTempFiles(context, intent); } else { setResultCode(RESULT_INVALID_ACTION); @@ -123,16 +124,16 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { } private boolean verifyIntentContents(Context context, Intent intent) { - if (MbmsDownloadManager.ACTION_DOWNLOAD_RESULT_INTERNAL.equals(intent.getAction())) { + if (VendorIntents.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."); return false; } - if (!intent.hasExtra(MbmsDownloadManager.EXTRA_REQUEST)) { + if (!intent.hasExtra(VendorIntents.EXTRA_REQUEST)) { Log.w(LOG_TAG, "Download result did not include the associated request. Ignoring."); return false; } - if (!intent.hasExtra(MbmsDownloadManager.EXTRA_TEMP_FILE_ROOT)) { + if (!intent.hasExtra(VendorIntents.EXTRA_TEMP_FILE_ROOT)) { Log.w(LOG_TAG, "Download result did not include the temp file root. Ignoring."); return false; } @@ -141,12 +142,12 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { "Ignoring."); return false; } - if (!intent.hasExtra(MbmsDownloadManager.EXTRA_FINAL_URI)) { + if (!intent.hasExtra(VendorIntents.EXTRA_FINAL_URI)) { Log.w(LOG_TAG, "Download result did not include the path to the final " + "temp file. Ignoring."); return false; } - DownloadRequest request = intent.getParcelableExtra(MbmsDownloadManager.EXTRA_REQUEST); + DownloadRequest request = intent.getParcelableExtra(VendorIntents.EXTRA_REQUEST); String expectedTokenFileName = request.getHash() + DOWNLOAD_TOKEN_SUFFIX; File expectedTokenFile = new File( MbmsUtils.getEmbmsTempFileDirForService(context, request.getFileServiceId()), @@ -156,27 +157,27 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { "Expected " + expectedTokenFile); return false; } - } else if (MbmsDownloadManager.ACTION_FILE_DESCRIPTOR_REQUEST.equals(intent.getAction())) { - if (!intent.hasExtra(MbmsDownloadManager.EXTRA_SERVICE_INFO)) { + } else if (VendorIntents.ACTION_FILE_DESCRIPTOR_REQUEST.equals(intent.getAction())) { + if (!intent.hasExtra(VendorIntents.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)) { + if (!intent.hasExtra(VendorIntents.EXTRA_TEMP_FILE_ROOT)) { Log.w(LOG_TAG, "Download result did not include the temp file root. Ignoring."); return false; } - } else if (MbmsDownloadManager.ACTION_CLEANUP.equals(intent.getAction())) { - if (!intent.hasExtra(MbmsDownloadManager.EXTRA_SERVICE_INFO)) { + } else if (VendorIntents.ACTION_CLEANUP.equals(intent.getAction())) { + if (!intent.hasExtra(VendorIntents.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)) { + if (!intent.hasExtra(VendorIntents.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)) { + if (!intent.hasExtra(VendorIntents.EXTRA_TEMP_FILES_IN_USE)) { Log.w(LOG_TAG, "Cleanup request did not include the list of temp files in use. " + "Ignoring."); return false; @@ -186,7 +187,7 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { } private void moveDownloadedFile(Context context, Intent intent) { - DownloadRequest request = intent.getParcelableExtra(MbmsDownloadManager.EXTRA_REQUEST); + DownloadRequest request = intent.getParcelableExtra(VendorIntents.EXTRA_REQUEST); Intent intentForApp = request.getIntentForApp(); int result = intent.getIntExtra(MbmsDownloadManager.EXTRA_RESULT, @@ -200,7 +201,7 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { } Uri destinationUri = request.getDestinationUri(); - Uri finalTempFile = intent.getParcelableExtra(MbmsDownloadManager.EXTRA_FINAL_URI); + Uri finalTempFile = intent.getParcelableExtra(VendorIntents.EXTRA_FINAL_URI); if (!verifyTempFilePath(context, request.getFileServiceId(), finalTempFile)) { Log.w(LOG_TAG, "Download result specified an invalid temp file " + finalTempFile); setResultCode(RESULT_DOWNLOAD_FINALIZATION_ERROR); @@ -225,13 +226,13 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { } private void cleanupPostMove(Context context, Intent intent) { - DownloadRequest request = intent.getParcelableExtra(MbmsDownloadManager.EXTRA_REQUEST); + DownloadRequest request = intent.getParcelableExtra(VendorIntents.EXTRA_REQUEST); if (request == null) { Log.w(LOG_TAG, "Intent does not include a DownloadRequest. Ignoring."); return; } - List tempFiles = intent.getParcelableExtra(MbmsDownloadManager.EXTRA_TEMP_LIST); + List tempFiles = intent.getParcelableExtra(VendorIntents.EXTRA_TEMP_LIST); if (tempFiles == null) { return; } @@ -246,15 +247,15 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { private void generateTempFiles(Context context, Intent intent) { FileServiceInfo serviceInfo = - intent.getParcelableExtra(MbmsDownloadManager.EXTRA_SERVICE_INFO); + intent.getParcelableExtra(VendorIntents.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); - List pausedList = intent.getParcelableExtra(MbmsDownloadManager.EXTRA_PAUSED_LIST); + int fdCount = intent.getIntExtra(VendorIntents.EXTRA_FD_COUNT, 0); + List pausedList = intent.getParcelableExtra(VendorIntents.EXTRA_PAUSED_LIST); if (fdCount == 0 && (pausedList == null || pausedList.size() == 0)) { Log.i(LOG_TAG, "No temp files actually requested. Ending."); @@ -269,8 +270,8 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { generateUrisForPausedFiles(context, serviceInfo, pausedList); Bundle result = new Bundle(); - result.putParcelableArrayList(MbmsDownloadManager.EXTRA_FREE_URI_LIST, freshTempFiles); - result.putParcelableArrayList(MbmsDownloadManager.EXTRA_PAUSED_URI_LIST, pausedFiles); + result.putParcelableArrayList(VendorIntents.EXTRA_FREE_URI_LIST, freshTempFiles); + result.putParcelableArrayList(VendorIntents.EXTRA_PAUSED_URI_LIST, pausedFiles); setResultCode(RESULT_OK); setResultExtras(result); } @@ -353,11 +354,11 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { private void cleanupTempFiles(Context context, Intent intent) { FileServiceInfo serviceInfo = - intent.getParcelableExtra(MbmsDownloadManager.EXTRA_SERVICE_INFO); + intent.getParcelableExtra(VendorIntents.EXTRA_SERVICE_INFO); File tempFileDir = MbmsUtils.getEmbmsTempFileDirForService(context, serviceInfo.getServiceId()); final List filesInUse = - intent.getParcelableArrayListExtra(MbmsDownloadManager.EXTRA_TEMP_FILES_IN_USE); + intent.getParcelableArrayListExtra(VendorIntents.EXTRA_TEMP_FILES_IN_USE); File[] filesToDelete = tempFileDir.listFiles(new FileFilter() { @Override public boolean accept(File file) { diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java index a0834eb6864fa..71713d013f975 100644 --- a/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java +++ b/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java @@ -18,6 +18,7 @@ package android.telephony.mbms.vendor; import android.annotation.NonNull; import android.os.RemoteException; +import android.telephony.mbms.DownloadProgressListener; import android.telephony.mbms.DownloadRequest; import android.telephony.mbms.FileInfo; import android.telephony.mbms.FileServiceInfo; @@ -59,8 +60,8 @@ public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub { * @hide */ @Override - public int initialize(int subscriptionId, - IMbmsDownloadManagerCallback callback) throws RemoteException { + public final int initialize(int subscriptionId, + final IMbmsDownloadManagerCallback callback) throws RemoteException { return initialize(subscriptionId, new MbmsDownloadManagerCallback() { @Override public void error(int errorCode, String message) throws RemoteException { @@ -133,12 +134,29 @@ public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub { * @param downloadRequest An object describing the set of files to be downloaded. * @param listener A listener through which the middleware can provide progress updates to * the app while both are still running. - * @return TODO: enumerate possible return values + * @return Any error from {@link android.telephony.mbms.MbmsException.GeneralErrors} + * or {@link MbmsException#SUCCESS} + */ + public int download(DownloadRequest downloadRequest, DownloadProgressListener listener) { + return 0; + } + + /** + * Actual AIDL implementation -- hides the callback AIDL from the API. + * @hide */ @Override - public int download(DownloadRequest downloadRequest, IDownloadProgressListener listener) + public final int download(DownloadRequest downloadRequest, IDownloadProgressListener listener) throws RemoteException { - return 0; + return download(downloadRequest, new DownloadProgressListener() { + @Override + public void progress(DownloadRequest request, FileInfo fileInfo, int + currentDownloadSize, int fullDownloadSize, int currentDecodedSize, int + fullDecodedSize) throws RemoteException { + listener.progress(request, fileInfo, currentDownloadSize, fullDownloadSize, + currentDecodedSize, fullDecodedSize); + } + }); } diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java index 0579d7e1ea9e9..8f2786f864ac5 100644 --- a/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java +++ b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java @@ -47,10 +47,10 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub { * or {@link MbmsException#SUCCESS}. Non-successful error codes will be passed to the app via * {@link IMbmsStreamingManagerCallback#error(int, String)}. * - * @param listener The callback to use to communicate with the app. + * @param callback The callback to use to communicate with the app. * @param subscriptionId The subscription ID to use. */ - public int initialize(MbmsStreamingManagerCallback listener, int subscriptionId) + public int initialize(MbmsStreamingManagerCallback callback, int subscriptionId) throws RemoteException { return 0; } @@ -60,10 +60,10 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub { * @hide */ @Override - public final int initialize(IMbmsStreamingManagerCallback listener, final int subscriptionId) - throws RemoteException { + public final int initialize(final IMbmsStreamingManagerCallback callback, + final int subscriptionId) throws RemoteException { final int uid = Binder.getCallingUid(); - listener.asBinder().linkToDeath(new DeathRecipient() { + callback.asBinder().linkToDeath(new DeathRecipient() { @Override public void binderDied() { onAppCallbackDied(uid, subscriptionId); @@ -74,7 +74,7 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub { @Override public void onError(int errorCode, String message) { try { - listener.error(errorCode, message); + callback.error(errorCode, message); } catch (RemoteException e) { onAppCallbackDied(uid, subscriptionId); } @@ -83,7 +83,7 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub { @Override public void onStreamingServicesUpdated(List services) { try { - listener.streamingServicesUpdated(services); + callback.streamingServicesUpdated(services); } catch (RemoteException e) { onAppCallbackDied(uid, subscriptionId); } @@ -92,7 +92,7 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub { @Override public void onMiddlewareReady() { try { - listener.middlewareReady(); + callback.middlewareReady(); } catch (RemoteException e) { onAppCallbackDied(uid, subscriptionId); } @@ -133,11 +133,11 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub { * * @param subscriptionId The subscription id to use. * @param serviceId The ID of the streaming service that the app has requested. - * @param listener The listener object on which the app wishes to receive updates. + * @param callback The callback object on which the app wishes to receive updates. * @return Any error in {@link android.telephony.mbms.MbmsException.GeneralErrors} */ public int startStreaming(int subscriptionId, String serviceId, - StreamingServiceCallback listener) throws RemoteException { + StreamingServiceCallback callback) throws RemoteException { return 0; } @@ -148,9 +148,9 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub { */ @Override public int startStreaming(int subscriptionId, String serviceId, - IStreamingServiceCallback listener) throws RemoteException { + IStreamingServiceCallback callback) throws RemoteException { final int uid = Binder.getCallingUid(); - listener.asBinder().linkToDeath(new DeathRecipient() { + callback.asBinder().linkToDeath(new DeathRecipient() { @Override public void binderDied() { onAppCallbackDied(uid, subscriptionId); @@ -161,7 +161,7 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub { @Override public void onError(int errorCode, String message) { try { - listener.error(errorCode, message); + callback.error(errorCode, message); } catch (RemoteException e) { onAppCallbackDied(uid, subscriptionId); } @@ -171,7 +171,7 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub { public void onStreamStateUpdated(@StreamingService.StreamingState int state, @StreamingService.StreamingStateChangeReason int reason) { try { - listener.streamStateUpdated(state, reason); + callback.streamStateUpdated(state, reason); } catch (RemoteException e) { onAppCallbackDied(uid, subscriptionId); } @@ -180,7 +180,7 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub { @Override public void onMediaDescriptionUpdated() { try { - listener.mediaDescriptionUpdated(); + callback.mediaDescriptionUpdated(); } catch (RemoteException e) { onAppCallbackDied(uid, subscriptionId); } @@ -189,7 +189,7 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub { @Override public void onBroadcastSignalStrengthUpdated(int signalStrength) { try { - listener.broadcastSignalStrengthUpdated(signalStrength); + callback.broadcastSignalStrengthUpdated(signalStrength); } catch (RemoteException e) { onAppCallbackDied(uid, subscriptionId); } @@ -198,7 +198,7 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub { @Override public void onStreamMethodUpdated(int methodType) { try { - listener.streamMethodUpdated(methodType); + callback.streamMethodUpdated(methodType); } catch (RemoteException e) { onAppCallbackDied(uid, subscriptionId); } diff --git a/telephony/java/android/telephony/mbms/vendor/VendorIntents.java b/telephony/java/android/telephony/mbms/vendor/VendorIntents.java new file mode 100644 index 0000000000000..367c995c6f7d3 --- /dev/null +++ b/telephony/java/android/telephony/mbms/vendor/VendorIntents.java @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2017 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 android.telephony.mbms.vendor; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ResolveInfo; +import android.net.Uri; +import android.telephony.mbms.DownloadRequest; +import android.telephony.mbms.MbmsDownloadReceiver; + +import java.io.File; +import java.util.List; + +/** + * @hide + * TODO: future systemapi + */ +public class VendorIntents { + + /** + * The MBMS middleware should send this when a download of single file has completed or + * failed. Mandatory extras are + * {@link android.telephony.MbmsDownloadManager#EXTRA_RESULT} + * {@link android.telephony.MbmsDownloadManager#EXTRA_FILE_INFO} + * {@link #EXTRA_REQUEST} + * {@link #EXTRA_TEMP_LIST} + * {@link #EXTRA_FINAL_URI} + */ + public static final String ACTION_DOWNLOAD_RESULT_INTERNAL = + "android.telephony.mbms.action.DOWNLOAD_RESULT_INTERNAL"; + + /** + * The MBMS middleware should send this when it wishes to request {@code content://} URIs to + * serve as temp files for downloads or when it wishes to resume paused downloads. Mandatory + * extras are + * {@link #EXTRA_REQUEST} + * + * Optional extras are + * {@link #EXTRA_FD_COUNT} (0 if not present) + * {@link #EXTRA_PAUSED_LIST} (empty if not present) + */ + public static final String ACTION_FILE_DESCRIPTOR_REQUEST = + "android.telephony.mbms.action.FILE_DESCRIPTOR_REQUEST"; + + /** + * The MBMS middleware should send this when it wishes to clean up temp files in the app's + * filesystem. Mandatory extras are: + * {@link #EXTRA_TEMP_FILES_IN_USE} + */ + public static final String ACTION_CLEANUP = + "android.telephony.mbms.action.CLEANUP"; + + /** + * Extra containing a {@link List} of {@link Uri}s that were used as temp files for this + * completed file. These {@link Uri}s should have scheme {@code file://}, and the temp + * files will be deleted upon receipt of the intent. + * May be null. + */ + public static final String EXTRA_TEMP_LIST = "android.telephony.mbms.extra.TEMP_LIST"; + + /** + * Extra containing an integer indicating the number of temp files requested. + */ + public static final String EXTRA_FD_COUNT = "android.telephony.mbms.extra.FD_COUNT"; + + /** + * Extra containing a list of {@link Uri}s that the middleware is requesting access to via + * {@link #ACTION_FILE_DESCRIPTOR_REQUEST} in order to resume downloading. These {@link Uri}s + * should have scheme {@code file://}. + */ + public static final String EXTRA_PAUSED_LIST = "android.telephony.mbms.extra.PAUSED_LIST"; + + /** + * Extra containing a list of {@link android.telephony.mbms.UriPathPair}s, used in the + * response to {@link #ACTION_FILE_DESCRIPTOR_REQUEST}. These are temp files that are meant + * to be used for new file downloads. + */ + public static final String EXTRA_FREE_URI_LIST = "android.telephony.mbms.extra.FREE_URI_LIST"; + + /** + * Extra containing a list of {@link android.telephony.mbms.UriPathPair}s, used in the + * response to {@link #ACTION_FILE_DESCRIPTOR_REQUEST}. These + * {@link android.telephony.mbms.UriPathPair}s contain {@code content://} URIs that provide + * access to previously paused downloads. + */ + public static final String EXTRA_PAUSED_URI_LIST = + "android.telephony.mbms.extra.PAUSED_URI_LIST"; + + /** + * Extra containing a string that points to the middleware's knowledge of where the temp file + * root for the app is. The path should be a canonical path as returned by + * {@link File#getCanonicalPath()} + */ + public static final String EXTRA_TEMP_FILE_ROOT = + "android.telephony.mbms.extra.TEMP_FILE_ROOT"; + + /** + * Extra containing a list of {@link Uri}s indicating temp files which the middleware is + * still using. + */ + public static final String EXTRA_TEMP_FILES_IN_USE = + "android.telephony.mbms.extra.TEMP_FILES_IN_USE"; + + /** + * Extra containing the {@link DownloadRequest} for which the download result or file + * descriptor request is for. Must not be null. + */ + public static final String EXTRA_REQUEST = "android.telephony.mbms.extra.REQUEST"; + + /** + * Extra containing a single {@link Uri} indicating the path to the temp file in which the + * decoded downloaded file resides. Must not be null. + */ + public static final String EXTRA_FINAL_URI = "android.telephony.mbms.extra.FINAL_URI"; + + /** + * 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"; + + /** + * Retrieves the {@link ComponentName} for the {@link android.content.BroadcastReceiver} that + * the various intents from the middleware should be targeted towards. + * @param uid The uid of the frontend app. + * @return The component name of the receiver that the middleware should send its intents to, + * or null if the app didn't declare it in the manifest. + */ + public static ComponentName getAppReceiverFromUid(Context context, int uid) { + String[] packageNames = context.getPackageManager().getPackagesForUid(uid); + if (packageNames == null) { + return null; + } + + for (String packageName : packageNames) { + ComponentName candidate = new ComponentName(packageName, + MbmsDownloadReceiver.class.getCanonicalName()); + Intent queryIntent = new Intent(); + queryIntent.setComponent(candidate); + List receivers = + context.getPackageManager().queryBroadcastReceivers(queryIntent, 0); + if (receivers != null && receivers.size() > 0) { + return candidate; + } + } + return null; + } +}