Merge notifySessionCreationFailed into notifyRequestFailed

Bug: 150582958
Test: Ran CTS and mediaroutertest
Change-Id: Ica95c7619d85565d49f238b46d3043358c94a37f
diff --git a/api/current.txt b/api/current.txt
index 255128c..1ef08e3 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -26899,7 +26899,6 @@
     method public final void notifyRequestFailed(long, int);
     method public final void notifyRoutes(@NonNull java.util.Collection<android.media.MediaRoute2Info>);
     method public final void notifySessionCreated(@NonNull android.media.RoutingSessionInfo, long);
-    method public final void notifySessionCreationFailed(long);
     method public final void notifySessionReleased(@NonNull String);
     method public final void notifySessionUpdated(@NonNull android.media.RoutingSessionInfo);
     method @CallSuper @Nullable public android.os.IBinder onBind(@NonNull android.content.Intent);
diff --git a/media/java/android/media/IMediaRoute2ProviderServiceCallback.aidl b/media/java/android/media/IMediaRoute2ProviderServiceCallback.aidl
index ab42d75..882caad 100644
--- a/media/java/android/media/IMediaRoute2ProviderServiceCallback.aidl
+++ b/media/java/android/media/IMediaRoute2ProviderServiceCallback.aidl
@@ -28,7 +28,6 @@
     // TODO: Change it to updateRoutes?
     void updateState(in MediaRoute2ProviderInfo providerInfo);
     void notifySessionCreated(in RoutingSessionInfo sessionInfo, long requestId);
-    void notifySessionCreationFailed(long requestId);
     void notifySessionUpdated(in RoutingSessionInfo sessionInfo);
     void notifySessionReleased(in RoutingSessionInfo sessionInfo);
     void notifyRequestFailed(long requestId, int reason);
diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java
index aa0eda1..51696a4 100644
--- a/media/java/android/media/MediaRoute2ProviderService.java
+++ b/media/java/android/media/MediaRoute2ProviderService.java
@@ -233,6 +233,7 @@
         String sessionId = sessionInfo.getId();
         synchronized (mSessionLock) {
             if (mSessionInfo.containsKey(sessionId)) {
+                // TODO: Notify failure to the requester, and throw exception if needed.
                 Log.w(TAG, "Ignoring duplicate session id.");
                 return;
             }
@@ -253,24 +254,6 @@
     }
 
     /**
-     * Notifies clients of that the session could not be created.
-     *
-     * @param requestId id of the previous request to create the session provided in
-     *                  {@link #onCreateSession(long, String, String, Bundle)}.
-     * @see #onCreateSession(long, String, String, Bundle)
-     */
-    public final void notifySessionCreationFailed(long requestId) {
-        if (mRemoteCallback == null) {
-            return;
-        }
-        try {
-            mRemoteCallback.notifySessionCreationFailed(requestId);
-        } catch (RemoteException ex) {
-            Log.w(TAG, "Failed to notify session creation failed.");
-        }
-    }
-
-    /**
      * Notifies the existing session is updated. For example, when
      * {@link RoutingSessionInfo#getSelectedRoutes() selected routes} are changed.
      */
@@ -364,7 +347,7 @@
      * {@link Bundle} which contains how to control the session.
      * <p>
      * If you can't create the session or want to reject the request, call
-     * {@link #notifySessionCreationFailed(long)} with the given {@code requestId}.
+     * {@link #notifyRequestFailed(long, int)} with the given {@code requestId}.
      *
      * @param requestId the id of this request
      * @param packageName the package name of the application that selected the route
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/SampleMediaRoute2ProviderService.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/SampleMediaRoute2ProviderService.java
index 0e7c7fc..22c5bce 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/SampleMediaRoute2ProviderService.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/SampleMediaRoute2ProviderService.java
@@ -216,8 +216,7 @@
             @Nullable Bundle sessionHints) {
         MediaRoute2Info route = mRoutes.get(routeId);
         if (route == null || TextUtils.equals(ROUTE_ID3_SESSION_CREATION_FAILED, routeId)) {
-            // Tell the router that session cannot be created by passing null as sessionInfo.
-            notifySessionCreationFailed(requestId);
+            notifyRequestFailed(requestId, REASON_UNKNOWN_ERROR);
             return;
         }
         maybeDeselectRoute(routeId);
diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java
index f144405..4cb1ed9 100644
--- a/services/core/java/com/android/server/media/MediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java
@@ -111,7 +111,6 @@
         void onProviderStateChanged(@Nullable MediaRoute2Provider provider);
         void onSessionCreated(@NonNull MediaRoute2Provider provider,
                 @Nullable RoutingSessionInfo sessionInfo, long requestId);
-        void onSessionCreationFailed(@NonNull MediaRoute2Provider provider, long requestId);
         void onSessionUpdated(@NonNull MediaRoute2Provider provider,
                 @NonNull RoutingSessionInfo sessionInfo);
         void onSessionReleased(@NonNull MediaRoute2Provider provider,
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
index e64776c..36a7bd9 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
@@ -328,19 +328,6 @@
         mCallback.onSessionCreated(this, sessionInfo, requestId);
     }
 
-    private void onSessionCreationFailed(Connection connection, long requestId) {
-        if (mActiveConnection != connection) {
-            return;
-        }
-
-        if (requestId == MediaRoute2ProviderService.REQUEST_ID_NONE) {
-            Slog.w(TAG, "onSessionCreationFailed: Ignoring requestId REQUEST_ID_NONE");
-            return;
-        }
-
-        mCallback.onSessionCreationFailed(this, requestId);
-    }
-
     private void onSessionUpdated(Connection connection, RoutingSessionInfo sessionInfo) {
         if (mActiveConnection != connection) {
             return;
@@ -543,10 +530,6 @@
             mHandler.post(() -> onSessionCreated(Connection.this, sessionInfo, requestId));
         }
 
-        void postSessionCreationFailed(long requestId) {
-            mHandler.post(() -> onSessionCreationFailed(Connection.this, requestId));
-        }
-
         void postSessionUpdated(RoutingSessionInfo sessionInfo) {
             mHandler.post(() -> onSessionUpdated(Connection.this, sessionInfo));
         }
@@ -555,7 +538,7 @@
             mHandler.post(() -> onSessionReleased(Connection.this, sessionInfo));
         }
 
-        void postSessionReleased(long requestId, int reason) {
+        void postRequestFailed(long requestId, int reason) {
             mHandler.post(() -> onRequestFailed(Connection.this, requestId, reason));
         }
     }
@@ -589,14 +572,6 @@
         }
 
         @Override
-        public void notifySessionCreationFailed(long requestId) {
-            Connection connection = mConnectionRef.get();
-            if (connection != null) {
-                connection.postSessionCreationFailed(requestId);
-            }
-        }
-
-        @Override
         public void notifySessionUpdated(RoutingSessionInfo sessionInfo) {
             Connection connection = mConnectionRef.get();
             if (connection != null) {
@@ -616,7 +591,7 @@
         public void notifyRequestFailed(long requestId, int reason) {
             Connection connection = mConnectionRef.get();
             if (connection != null) {
-                connection.postSessionReleased(requestId, reason);
+                connection.postRequestFailed(requestId, reason);
             }
         }
     }
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index e78a35c..16f2add 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -608,7 +608,8 @@
         routerRecord.mUserRecord.mHandler.sendMessage(
                 obtainMessage(UserHandler::requestCreateSessionOnHandler,
                         routerRecord.mUserRecord.mHandler,
-                        routerRecord, route, uniqueRequestId, sessionHints));
+                        routerRecord, /* managerRecord= */ null, route, uniqueRequestId,
+                        sessionHints));
     }
 
     private void selectRouteWithRouter2Locked(@NonNull IMediaRouter2 router,
@@ -788,7 +789,8 @@
         routerRecord.mUserRecord.mHandler.sendMessage(
                 obtainMessage(UserHandler::requestCreateSessionOnHandler,
                         routerRecord.mUserRecord.mHandler,
-                        routerRecord, route, uniqueRequestId, null /* sessionHints */));
+                        routerRecord, managerRecord, route, uniqueRequestId,
+                        /* sessionHints= */ null));
     }
 
     private void selectRouteWithManagerLocked(@NonNull IMediaRouter2Manager manager,
@@ -927,7 +929,7 @@
         return ((long) routerOrManagerId << 32) | originalRequestId;
     }
 
-    static int toRouterOrManagerId(long uniqueRequestId) {
+    static int toRequesterId(long uniqueRequestId) {
         return (int) (uniqueRequestId >> 32);
     }
 
@@ -1107,11 +1109,6 @@
                     this, provider, sessionInfo, requestId));
         }
 
-        @Override
-        public void onSessionCreationFailed(@NonNull MediaRoute2Provider provider, long requestId) {
-            sendMessage(PooledLambda.obtainMessage(UserHandler::onSessionCreationFailedOnHandler,
-                    this, provider, requestId));
-        }
 
         @Override
         public void onSessionUpdated(@NonNull MediaRoute2Provider provider,
@@ -1223,7 +1220,8 @@
         }
 
         private void requestCreateSessionOnHandler(@NonNull RouterRecord routerRecord,
-                @NonNull MediaRoute2Info route, long requestId, @Nullable Bundle sessionHints) {
+                @Nullable ManagerRecord managerRecord, @NonNull MediaRoute2Info route,
+                long requestId, @Nullable Bundle sessionHints) {
 
             final MediaRoute2Provider provider = findProvider(route.getProviderId());
             if (provider == null) {
@@ -1235,7 +1233,7 @@
 
             // TODO: Apply timeout for each request (How many seconds should we wait?)
             SessionCreationRequest request =
-                    new SessionCreationRequest(routerRecord, route, requestId);
+                    new SessionCreationRequest(routerRecord, managerRecord, route, requestId);
             mSessionCreationRequests.add(request);
 
             provider.requestCreateSession(routerRecord.mPackageName, route.getOriginalId(),
@@ -1421,30 +1419,6 @@
             mSessionToRouterMap.put(sessionInfo.getId(), routerRecord);
         }
 
-        private void onSessionCreationFailedOnHandler(@NonNull MediaRoute2Provider provider,
-                long requestId) {
-            SessionCreationRequest matchingRequest = null;
-
-            for (SessionCreationRequest request : mSessionCreationRequests) {
-                if (request.mRequestId == requestId
-                        && TextUtils.equals(
-                                request.mRoute.getProviderId(), provider.getUniqueId())) {
-                    matchingRequest = request;
-                    break;
-                }
-            }
-
-            if (matchingRequest == null) {
-                Slog.w(TAG, "Ignoring session creation failed result for unknown request. "
-                        + "requestId=" + requestId);
-                return;
-            }
-
-            mSessionCreationRequests.remove(matchingRequest);
-            notifySessionCreationFailedToRouter(matchingRequest.mRouterRecord,
-                    toOriginalRequestId(requestId));
-        }
-
         private void onSessionInfoChangedOnHandler(@NonNull MediaRoute2Provider provider,
                 @NonNull RoutingSessionInfo sessionInfo) {
             List<IMediaRouter2Manager> managers = getManagers();
@@ -1483,30 +1457,56 @@
 
         private void onRequestFailedOnHandler(@NonNull MediaRoute2Provider provider,
                 long requestId, int reason) {
-            final int managerId = toRouterOrManagerId(requestId);
-
-            MediaRouter2ServiceImpl service = mServiceRef.get();
-            if (service == null) {
+            if (handleSessionCreationRequestFailed(provider, requestId, reason)) {
                 return;
             }
 
-            ManagerRecord managerToNotifyFailure = null;
-            synchronized (service.mLock) {
-                for (ManagerRecord manager : mUserRecord.mManagerRecords) {
-                    if (manager.mManagerId == managerId) {
-                        managerToNotifyFailure = manager;
-                        break;
-                    }
+            final int requesterId = toRequesterId(requestId);
+            for (ManagerRecord manager : getManagerRecords()) {
+                if (manager.mManagerId == requesterId) {
+                    notifyRequestFailedToManager(
+                            manager.mManager, toOriginalRequestId(requestId), reason);
+                    return;
                 }
             }
 
-            if (managerToNotifyFailure == null) {
-                Slog.w(TAG, "No matching managerRecord found for managerId=" + managerId);
-                return;
+            // Currently, only the manager can get notified of failures.
+            // TODO: Notify router too when the related callback is introduced.
+        }
+
+        // TODO: Find a way to prevent providers from notifying error on random requestId.
+        //       Solutions can be:
+        //       1) Record the other type of requests too (not only session creation request)
+        //       2) Throw exception on providers when they try to notify error on random requestId.
+        private boolean handleSessionCreationRequestFailed(@NonNull MediaRoute2Provider provider,
+                long requestId, int reason) {
+            // Check whether the failure is about creating a session
+            SessionCreationRequest matchingRequest = null;
+            for (SessionCreationRequest request : mSessionCreationRequests) {
+                if (request.mRequestId == requestId && TextUtils.equals(
+                        request.mRoute.getProviderId(), provider.getUniqueId())) {
+                    matchingRequest = request;
+                    break;
+                }
             }
 
-            notifyRequestFailedToManager(
-                    managerToNotifyFailure.mManager, toOriginalRequestId(requestId), reason);
+            if (matchingRequest == null) {
+                // The failure is not about creating a session.
+                return false;
+            }
+
+            mSessionCreationRequests.remove(matchingRequest);
+
+            // Notify the requester about the failure.
+            // The call should be made by either MediaRouter2 or MediaRouter2Manager.
+            if (matchingRequest.mRequestedManagerRecord == null) {
+                notifySessionCreationFailedToRouter(
+                        matchingRequest.mRouterRecord, toOriginalRequestId(requestId));
+            } else {
+                notifyRequestFailedToManager(matchingRequest.mRequestedManagerRecord.mManager,
+                        toOriginalRequestId(requestId), reason);
+            }
+            return true;
         }
 
         private void notifySessionCreatedToRouter(@NonNull RouterRecord routerRecord,
@@ -1596,6 +1596,16 @@
             return managers;
         }
 
+        private List<ManagerRecord> getManagerRecords() {
+            MediaRouter2ServiceImpl service = mServiceRef.get();
+            if (service == null) {
+                return new ArrayList<>();
+            }
+            synchronized (service.mLock) {
+                return new ArrayList<>(mUserRecord.mManagerRecords);
+            }
+        }
+
         private void notifyRoutesToRouter(@NonNull IMediaRouter2 router) {
             List<MediaRoute2Info> routes = new ArrayList<>();
             for (MediaRoute2ProviderInfo providerInfo : mLastProviderInfos) {
@@ -1789,12 +1799,16 @@
 
         final class SessionCreationRequest {
             public final RouterRecord mRouterRecord;
+            public final ManagerRecord mRequestedManagerRecord;
             public final MediaRoute2Info mRoute;
             public final long mRequestId;
 
+            // requestedManagerRecord is not null only when the request is made by manager.
             SessionCreationRequest(@NonNull RouterRecord routerRecord,
+                    @Nullable ManagerRecord requestedManagerRecord,
                     @NonNull MediaRoute2Info route, long requestId) {
                 mRouterRecord = routerRecord;
+                mRequestedManagerRecord = requestedManagerRecord;
                 mRoute = route;
                 mRequestId = requestId;
             }