Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d5c955fc authored by Hall Liu's avatar Hall Liu
Browse files

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.

Change-Id: Ie15283b5c34fee736e8023dbd4f889c2ca95299e
parent b0563246
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -40419,7 +40419,7 @@ package android.telephony.mbms {
    field public static final int REASON_BY_USER_REQUEST = 1; // 0x1
    field public static final int REASON_END_OF_SESSION = 2; // 0x2
    field public static final int REASON_FREQUENCY_CONFLICT = 3; // 0x3
    field public static final int REASON_LEFT_MBMS_BROADCAST_AREA = 5; // 0x5
    field public static final int REASON_LEFT_MBMS_BROADCAST_AREA = 6; // 0x6
    field public static final int REASON_NONE = 0; // 0x0
    field public static final int REASON_NOT_CONNECTED_TO_HOMECARRIER_LTE = 5; // 0x5
    field public static final int REASON_OUT_OF_MEMORY = 4; // 0x4
+1 −1
Original line number Diff line number Diff line
@@ -43933,7 +43933,7 @@ package android.telephony.mbms {
    field public static final int REASON_BY_USER_REQUEST = 1; // 0x1
    field public static final int REASON_END_OF_SESSION = 2; // 0x2
    field public static final int REASON_FREQUENCY_CONFLICT = 3; // 0x3
    field public static final int REASON_LEFT_MBMS_BROADCAST_AREA = 5; // 0x5
    field public static final int REASON_LEFT_MBMS_BROADCAST_AREA = 6; // 0x6
    field public static final int REASON_NONE = 0; // 0x0
    field public static final int REASON_NOT_CONNECTED_TO_HOMECARRIER_LTE = 5; // 0x5
    field public static final int REASON_OUT_OF_MEMORY = 4; // 0x4
+1 −1
Original line number Diff line number Diff line
@@ -40641,7 +40641,7 @@ package android.telephony.mbms {
    field public static final int REASON_BY_USER_REQUEST = 1; // 0x1
    field public static final int REASON_END_OF_SESSION = 2; // 0x2
    field public static final int REASON_FREQUENCY_CONFLICT = 3; // 0x3
    field public static final int REASON_LEFT_MBMS_BROADCAST_AREA = 5; // 0x5
    field public static final int REASON_LEFT_MBMS_BROADCAST_AREA = 6; // 0x6
    field public static final int REASON_NONE = 0; // 0x0
    field public static final int REASON_NOT_CONNECTED_TO_HOMECARRIER_LTE = 5; // 0x5
    field public static final int REASON_OUT_OF_MEMORY = 4; // 0x4
+60 −11
Original line number Diff line number Diff line
@@ -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<IMbmsDownloadService> 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);
        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.
        }
    }
}
+69 −21
Original line number Diff line number Diff line
@@ -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;
@@ -57,7 +58,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<IMbmsStreamingService> 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;
@@ -81,6 +92,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.
@@ -92,9 +115,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);
        try {
            manager.bindAndInitialize();
        } catch (MbmsException e) {
            sIsInitialized.set(false);
            throw e;
        }
        return manager;
    }

@@ -126,17 +157,19 @@ public class MbmsStreamingManager {
     * May throw an {@link IllegalStateException}
     */
    public void dispose() {
        try {
            IMbmsStreamingService streamingService = mService.get();
            if (streamingService == null) {
                // Ignore and return, assume already disposed.
                return;
            }
        try {
            streamingService.dispose(mSubscriptionId);
        } catch (RemoteException e) {
            // Ignore for now
        }
        } finally {
            mService.set(null);
            sIsInitialized.set(false);
        }
    }

    /**
@@ -170,6 +203,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);
        }
    }
@@ -222,6 +256,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);
        }

@@ -241,26 +276,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,
                            sendErrorToApp(
                                    MbmsException.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE,
                                    e.toString());
                            } catch (RemoteException e1) {
                                // ignore
                            }
                            sIsInitialized.set(false);
                            return;
                        }
                        if (result != MbmsException.SUCCESS) {
                            sendErrorToApp(result, "Error returned during initialization");
                            sIsInitialized.set(false);
                            return;
                        }
                        try {
                                mInternalCallback.error(
                                        result, "Error returned during initialization");
                            streamingService.asBinder().linkToDeath(mDeathRecipient, 0);
                        } catch (RemoteException e) {
                                // ignore
                            }
                            sendErrorToApp(MbmsException.ERROR_MIDDLEWARE_LOST,
                                    "Middleware lost during initialization");
                            sIsInitialized.set(false);
                            return;
                        }
                        mService.set(streamingService);
@@ -268,8 +307,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.
        }
    }
}
Loading