blob: cc9503995ad97a60d6ff5706bea339c887d0ca43 [file] [log] [blame]
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001/*
2 * Copyright 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.media;
18
Kyunglyul Hyunf0eb51b2020-04-14 19:56:16 +090019import static android.media.MediaRoute2ProviderService.REASON_UNKNOWN_ERROR;
Hyundo Moonb26c4b22020-01-08 19:44:43 +090020import static android.media.MediaRouter2Utils.getOriginalId;
21import static android.media.MediaRouter2Utils.getProviderId;
22
Kyunglyul Hyun13bc1052019-05-31 17:00:36 +090023import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
24
Kyunglyul Hyundafac542019-04-29 18:07:21 +090025import android.annotation.NonNull;
Kyunglyul Hyunc6583832020-01-17 11:11:46 +000026import android.annotation.Nullable;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +090027import android.app.ActivityManager;
28import android.content.Context;
Kyunglyul Hyundafac542019-04-29 18:07:21 +090029import android.content.pm.PackageManager;
Hyundo Moon56337492020-02-16 16:19:54 +090030import android.media.IMediaRouter2;
Kyunglyul Hyun3aedf022019-04-15 16:38:19 +090031import android.media.IMediaRouter2Manager;
Kyunglyul Hyuncaae8dc2019-04-29 15:45:23 +090032import android.media.MediaRoute2Info;
Kyunglyul Hyun3aedf022019-04-15 16:38:19 +090033import android.media.MediaRoute2ProviderInfo;
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +090034import android.media.MediaRoute2ProviderService;
35import android.media.MediaRouter2Manager;
Kyunglyul Hyun616096e2020-01-09 16:15:03 +090036import android.media.RouteDiscoveryPreference;
Hyundo Moonf829e6f2020-01-11 19:31:35 +090037import android.media.RoutingSessionInfo;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +090038import android.os.Binder;
Kyunglyul Hyun7d720f72020-01-17 11:03:28 +000039import android.os.Bundle;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +090040import android.os.Handler;
41import android.os.IBinder;
Kyunglyul Hyun6c5d7dc2019-04-24 15:57:07 +090042import android.os.Looper;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +090043import android.os.RemoteException;
Kyunglyul Hyun23b3aaa2019-08-06 11:17:16 +090044import android.os.UserHandle;
Kyunglyul Hyun13bc1052019-05-31 17:00:36 +090045import android.text.TextUtils;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +090046import android.util.ArrayMap;
47import android.util.Log;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +090048import android.util.Slog;
49import android.util.SparseArray;
50
Kyunglyul Hyundafac542019-04-29 18:07:21 +090051import com.android.internal.annotations.GuardedBy;
Kyunglyul Hyun30e2c652019-07-11 16:25:31 +090052import com.android.internal.util.function.pooled.PooledLambda;
Kyunglyul Hyundafac542019-04-29 18:07:21 +090053
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +090054import java.io.PrintWriter;
55import java.lang.ref.WeakReference;
56import java.util.ArrayList;
Kyunglyul Hyun7af73012019-10-11 20:01:30 +090057import java.util.Collection;
Kyunglyul Hyundafac542019-04-29 18:07:21 +090058import java.util.Collections;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +090059import java.util.List;
Hyundo Moon0a926572019-12-28 15:01:21 +090060import java.util.Map;
Kyunglyul Hyundafac542019-04-29 18:07:21 +090061import java.util.Objects;
Hyundo Moon63a05402019-12-19 20:13:56 +090062import java.util.concurrent.CopyOnWriteArrayList;
Kyunglyul Hyunc7847242019-12-30 17:46:04 +090063import java.util.concurrent.atomic.AtomicInteger;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +090064
65/**
Kyunglyul Hyunc6583832020-01-17 11:11:46 +000066 * Implements features related to {@link android.media.MediaRouter2} and
67 * {@link android.media.MediaRouter2Manager}.
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +090068 */
69class MediaRouter2ServiceImpl {
Hyundo Moon7d3ab332019-10-16 11:09:56 +090070 private static final String TAG = "MR2ServiceImpl";
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +090071 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
72
Hyundo Moon8ca032d2020-03-31 15:45:45 +090073 // TODO: (In Android S or later) if we add callback methods for generic failures
74 // in MediaRouter2, remove this constant and replace the usages with the real request IDs.
Hyundo Moon0fa60e82020-02-14 11:44:45 +090075 private static final long DUMMY_REQUEST_ID = -1;
76
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +090077 private final Context mContext;
78 private final Object mLock = new Object();
Hyundo Moon56337492020-02-16 16:19:54 +090079 final AtomicInteger mNextRouterOrManagerId = new AtomicInteger(1);
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +090080
Kyunglyul Hyundafac542019-04-29 18:07:21 +090081 @GuardedBy("mLock")
82 private final SparseArray<UserRecord> mUserRecords = new SparseArray<>();
83 @GuardedBy("mLock")
Hyundo Moon56337492020-02-16 16:19:54 +090084 private final ArrayMap<IBinder, RouterRecord> mAllRouterRecords = new ArrayMap<>();
Kyunglyul Hyundafac542019-04-29 18:07:21 +090085 @GuardedBy("mLock")
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +090086 private final ArrayMap<IBinder, ManagerRecord> mAllManagerRecords = new ArrayMap<>();
Kyunglyul Hyundafac542019-04-29 18:07:21 +090087 @GuardedBy("mLock")
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +090088 private int mCurrentUserId = -1;
89
90 MediaRouter2ServiceImpl(Context context) {
91 mContext = context;
92 }
93
Hyundo Moone962ed42020-02-16 19:47:41 +090094 ////////////////////////////////////////////////////////////////
95 //// Calls from MediaRouter2
96 //// - Should not have @NonNull/@Nullable on any arguments
97 ////////////////////////////////////////////////////////////////
98
Hyundo Moon5736a612019-11-19 15:08:32 +090099 @NonNull
100 public List<MediaRoute2Info> getSystemRoutes() {
101 final int uid = Binder.getCallingUid();
Sungsoo Lim277ea282020-01-14 16:35:05 +0900102 final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
Sungsoo Limc27785a2020-03-27 16:57:47 +0900103 final boolean hasModifyAudioRoutingPermission = mContext.checkCallingOrSelfPermission(
104 android.Manifest.permission.MODIFY_AUDIO_ROUTING)
105 == PackageManager.PERMISSION_GRANTED;
Hyundo Moon5736a612019-11-19 15:08:32 +0900106
Sungsoo Limdfafaf72020-01-07 13:04:05 +0900107 final long token = Binder.clearCallingIdentity();
108 try {
109 Collection<MediaRoute2Info> systemRoutes;
110 synchronized (mLock) {
111 UserRecord userRecord = getOrCreateUserRecordLocked(userId);
Sungsoo Limc27785a2020-03-27 16:57:47 +0900112 if (hasModifyAudioRoutingPermission) {
113 MediaRoute2ProviderInfo providerInfo =
114 userRecord.mHandler.mSystemProvider.getProviderInfo();
115 if (providerInfo != null) {
116 systemRoutes = providerInfo.getRoutes();
117 } else {
118 systemRoutes = Collections.emptyList();
119 }
Sungsoo Limdfafaf72020-01-07 13:04:05 +0900120 } else {
Sungsoo Limc27785a2020-03-27 16:57:47 +0900121 systemRoutes = new ArrayList<>();
122 systemRoutes.add(userRecord.mHandler.mSystemProvider.getDefaultRoute());
Sungsoo Limdfafaf72020-01-07 13:04:05 +0900123 }
Hyundo Moon5736a612019-11-19 15:08:32 +0900124 }
Sungsoo Limdfafaf72020-01-07 13:04:05 +0900125 return new ArrayList<>(systemRoutes);
126 } finally {
127 Binder.restoreCallingIdentity(token);
Hyundo Moon5736a612019-11-19 15:08:32 +0900128 }
Hyundo Moon5736a612019-11-19 15:08:32 +0900129 }
130
Hyundo Moon67c41fd2020-01-17 14:22:42 +0900131 @NonNull
132 public RoutingSessionInfo getSystemSessionInfo() {
133 final int uid = Binder.getCallingUid();
134 final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
Sungsoo Limc27785a2020-03-27 16:57:47 +0900135 final boolean hasModifyAudioRoutingPermission = mContext.checkCallingOrSelfPermission(
136 android.Manifest.permission.MODIFY_AUDIO_ROUTING)
137 == PackageManager.PERMISSION_GRANTED;
Hyundo Moon67c41fd2020-01-17 14:22:42 +0900138
139 final long token = Binder.clearCallingIdentity();
140 try {
141 RoutingSessionInfo systemSessionInfo = null;
142 synchronized (mLock) {
143 UserRecord userRecord = getOrCreateUserRecordLocked(userId);
Sungsoo Limc27785a2020-03-27 16:57:47 +0900144 List<RoutingSessionInfo> sessionInfos;
145 if (hasModifyAudioRoutingPermission) {
146 sessionInfos = userRecord.mHandler.mSystemProvider.getSessionInfos();
147 if (sessionInfos != null && !sessionInfos.isEmpty()) {
148 systemSessionInfo = sessionInfos.get(0);
149 } else {
150 Slog.w(TAG, "System provider does not have any session info.");
151 }
Hyundo Moon67c41fd2020-01-17 14:22:42 +0900152 } else {
Sungsoo Limc27785a2020-03-27 16:57:47 +0900153 systemSessionInfo = userRecord.mHandler.mSystemProvider.getDefaultSessionInfo();
Hyundo Moon67c41fd2020-01-17 14:22:42 +0900154 }
155 }
156 return systemSessionInfo;
157 } finally {
158 Binder.restoreCallingIdentity(token);
159 }
160 }
161
Hyundo Moone962ed42020-02-16 19:47:41 +0900162 public void registerRouter2(IMediaRouter2 router, String packageName) {
Hyundo Moon56337492020-02-16 16:19:54 +0900163 Objects.requireNonNull(router, "router must not be null");
Hyundo Moone962ed42020-02-16 19:47:41 +0900164 if (TextUtils.isEmpty(packageName)) {
165 throw new IllegalArgumentException("packageName must not be empty");
166 }
Kyunglyul Hyundafac542019-04-29 18:07:21 +0900167
168 final int uid = Binder.getCallingUid();
169 final int pid = Binder.getCallingPid();
Sungsoo Lim277ea282020-01-14 16:35:05 +0900170 final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
Sungsoo Lim7065f1b2020-03-24 18:52:42 +0900171 final boolean hasConfigureWifiDisplayPermission = mContext.checkCallingOrSelfPermission(
Kyunglyul Hyundafac542019-04-29 18:07:21 +0900172 android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
173 == PackageManager.PERMISSION_GRANTED;
Sungsoo Lim7065f1b2020-03-24 18:52:42 +0900174 final boolean hasModifyAudioRoutingPermission = mContext.checkCallingOrSelfPermission(
175 android.Manifest.permission.MODIFY_AUDIO_ROUTING)
176 == PackageManager.PERMISSION_GRANTED;
177
Kyunglyul Hyundafac542019-04-29 18:07:21 +0900178 final long token = Binder.clearCallingIdentity();
179 try {
180 synchronized (mLock) {
Sungsoo Lim7065f1b2020-03-24 18:52:42 +0900181 registerRouter2Locked(router, uid, pid, packageName, userId,
182 hasConfigureWifiDisplayPermission, hasModifyAudioRoutingPermission);
Kyunglyul Hyundafac542019-04-29 18:07:21 +0900183 }
184 } finally {
185 Binder.restoreCallingIdentity(token);
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +0900186 }
Kyunglyul Hyundafac542019-04-29 18:07:21 +0900187 }
188
Hyundo Moone962ed42020-02-16 19:47:41 +0900189 public void unregisterRouter2(IMediaRouter2 router) {
Hyundo Moon56337492020-02-16 16:19:54 +0900190 Objects.requireNonNull(router, "router must not be null");
Kyunglyul Hyundafac542019-04-29 18:07:21 +0900191
192 final long token = Binder.clearCallingIdentity();
193 try {
194 synchronized (mLock) {
Hyundo Moon56337492020-02-16 16:19:54 +0900195 unregisterRouter2Locked(router, false);
Kyunglyul Hyundafac542019-04-29 18:07:21 +0900196 }
197 } finally {
198 Binder.restoreCallingIdentity(token);
199 }
200 }
201
Hyundo Moone962ed42020-02-16 19:47:41 +0900202 public void setDiscoveryRequestWithRouter2(IMediaRouter2 router,
203 RouteDiscoveryPreference preference) {
204 Objects.requireNonNull(router, "router must not be null");
205 Objects.requireNonNull(preference, "preference must not be null");
Kyunglyul Hyun23b3aaa2019-08-06 11:17:16 +0900206
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +0900207 final long token = Binder.clearCallingIdentity();
208 try {
209 synchronized (mLock) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900210 RouterRecord routerRecord = mAllRouterRecords.get(router.asBinder());
211 if (routerRecord == null) {
212 Slog.w(TAG, "Ignoring updating discoveryRequest of null routerRecord.");
213 return;
214 }
215 setDiscoveryRequestWithRouter2Locked(routerRecord, preference);
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +0900216 }
217 } finally {
218 Binder.restoreCallingIdentity(token);
219 }
220 }
221
Hyundo Moone962ed42020-02-16 19:47:41 +0900222 public void setRouteVolumeWithRouter2(IMediaRouter2 router,
223 MediaRoute2Info route, int volume) {
224 Objects.requireNonNull(router, "router must not be null");
225 Objects.requireNonNull(route, "route must not be null");
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +0900226
227 final long token = Binder.clearCallingIdentity();
228 try {
229 synchronized (mLock) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900230 setRouteVolumeWithRouter2Locked(router, route, volume);
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +0900231 }
232 } finally {
233 Binder.restoreCallingIdentity(token);
234 }
235 }
236
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900237 public void requestCreateSessionWithRouter2(IMediaRouter2 router, int requestId,
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900238 long managerRequestId, RoutingSessionInfo oldSession,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900239 MediaRoute2Info route, Bundle sessionHints) {
Hyundo Moon56337492020-02-16 16:19:54 +0900240 Objects.requireNonNull(router, "router must not be null");
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900241 Objects.requireNonNull(oldSession, "oldSession must not be null");
Hyundo Moon63a05402019-12-19 20:13:56 +0900242 Objects.requireNonNull(route, "route must not be null");
Hyundo Moon63a05402019-12-19 20:13:56 +0900243
244 final long token = Binder.clearCallingIdentity();
245 try {
246 synchronized (mLock) {
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900247 requestCreateSessionWithRouter2Locked(requestId, managerRequestId,
248 router, oldSession, route, sessionHints);
Kyunglyul Hyunf0eb51b2020-04-14 19:56:16 +0900249 }
250 } finally {
251 Binder.restoreCallingIdentity(token);
252 }
253 }
254
Hyundo Moon56337492020-02-16 16:19:54 +0900255 public void selectRouteWithRouter2(IMediaRouter2 router, String uniqueSessionId,
Hyundo Moon0a926572019-12-28 15:01:21 +0900256 MediaRoute2Info route) {
Hyundo Moon56337492020-02-16 16:19:54 +0900257 Objects.requireNonNull(router, "router must not be null");
Hyundo Moon0a926572019-12-28 15:01:21 +0900258 Objects.requireNonNull(route, "route must not be null");
Hyundo Moonb26c4b22020-01-08 19:44:43 +0900259 if (TextUtils.isEmpty(uniqueSessionId)) {
260 throw new IllegalArgumentException("uniqueSessionId must not be empty");
261 }
Hyundo Moon0a926572019-12-28 15:01:21 +0900262
263 final long token = Binder.clearCallingIdentity();
264 try {
265 synchronized (mLock) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900266 selectRouteWithRouter2Locked(router, uniqueSessionId, route);
Hyundo Moon0a926572019-12-28 15:01:21 +0900267 }
268 } finally {
269 Binder.restoreCallingIdentity(token);
270 }
271 }
272
Hyundo Moon56337492020-02-16 16:19:54 +0900273 public void deselectRouteWithRouter2(IMediaRouter2 router, String uniqueSessionId,
Hyundo Moon0a926572019-12-28 15:01:21 +0900274 MediaRoute2Info route) {
Hyundo Moon56337492020-02-16 16:19:54 +0900275 Objects.requireNonNull(router, "router must not be null");
Hyundo Moon0a926572019-12-28 15:01:21 +0900276 Objects.requireNonNull(route, "route must not be null");
Hyundo Moonb26c4b22020-01-08 19:44:43 +0900277 if (TextUtils.isEmpty(uniqueSessionId)) {
278 throw new IllegalArgumentException("uniqueSessionId must not be empty");
279 }
Hyundo Moon0a926572019-12-28 15:01:21 +0900280
281 final long token = Binder.clearCallingIdentity();
282 try {
283 synchronized (mLock) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900284 deselectRouteWithRouter2Locked(router, uniqueSessionId, route);
Hyundo Moon0a926572019-12-28 15:01:21 +0900285 }
286 } finally {
287 Binder.restoreCallingIdentity(token);
288 }
289 }
290
Hyundo Moon56337492020-02-16 16:19:54 +0900291 public void transferToRouteWithRouter2(IMediaRouter2 router, String uniqueSessionId,
Hyundo Moon0a926572019-12-28 15:01:21 +0900292 MediaRoute2Info route) {
Hyundo Moon56337492020-02-16 16:19:54 +0900293 Objects.requireNonNull(router, "router must not be null");
Hyundo Moon0a926572019-12-28 15:01:21 +0900294 Objects.requireNonNull(route, "route must not be null");
Hyundo Moonb26c4b22020-01-08 19:44:43 +0900295 if (TextUtils.isEmpty(uniqueSessionId)) {
296 throw new IllegalArgumentException("uniqueSessionId must not be empty");
297 }
Hyundo Moon0a926572019-12-28 15:01:21 +0900298
299 final long token = Binder.clearCallingIdentity();
300 try {
301 synchronized (mLock) {
Hyundo Moon56337492020-02-16 16:19:54 +0900302 transferToRouteWithRouter2Locked(router, uniqueSessionId, route);
Hyundo Moon0a926572019-12-28 15:01:21 +0900303 }
304 } finally {
305 Binder.restoreCallingIdentity(token);
306 }
307 }
308
Hyundo Moone962ed42020-02-16 19:47:41 +0900309 public void setSessionVolumeWithRouter2(IMediaRouter2 router, String uniqueSessionId,
310 int volume) {
311 Objects.requireNonNull(router, "router must not be null");
312 Objects.requireNonNull(uniqueSessionId, "uniqueSessionId must not be null");
313
314 final long token = Binder.clearCallingIdentity();
315 try {
316 synchronized (mLock) {
317 setSessionVolumeWithRouter2Locked(router, uniqueSessionId, volume);
318 }
319 } finally {
320 Binder.restoreCallingIdentity(token);
321 }
322 }
323
Hyundo Moon56337492020-02-16 16:19:54 +0900324 public void releaseSessionWithRouter2(IMediaRouter2 router, String uniqueSessionId) {
325 Objects.requireNonNull(router, "router must not be null");
Hyundo Moonb26c4b22020-01-08 19:44:43 +0900326 if (TextUtils.isEmpty(uniqueSessionId)) {
327 throw new IllegalArgumentException("uniqueSessionId must not be empty");
328 }
Hyundo Moonca9db782020-01-01 18:31:15 +0900329
330 final long token = Binder.clearCallingIdentity();
331 try {
332 synchronized (mLock) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900333 releaseSessionWithRouter2Locked(router, uniqueSessionId);
Hyundo Moonca9db782020-01-01 18:31:15 +0900334 }
335 } finally {
336 Binder.restoreCallingIdentity(token);
337 }
338 }
339
Hyundo Moone962ed42020-02-16 19:47:41 +0900340 ////////////////////////////////////////////////////////////////
341 //// Calls from MediaRouter2Manager
342 //// - Should not have @NonNull/@Nullable on any arguments
343 ////////////////////////////////////////////////////////////////
Kyunglyul Hyundafac542019-04-29 18:07:21 +0900344
Hyundo Moone962ed42020-02-16 19:47:41 +0900345 @NonNull
346 public List<RoutingSessionInfo> getActiveSessions(IMediaRouter2Manager manager) {
347 Objects.requireNonNull(manager, "manager must not be null");
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +0900348 final long token = Binder.clearCallingIdentity();
349 try {
350 synchronized (mLock) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900351 return getActiveSessionsLocked(manager);
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +0900352 }
353 } finally {
354 Binder.restoreCallingIdentity(token);
355 }
356 }
357
Hyundo Moone962ed42020-02-16 19:47:41 +0900358 public void registerManager(IMediaRouter2Manager manager, String packageName) {
359 Objects.requireNonNull(manager, "manager must not be null");
360 if (TextUtils.isEmpty(packageName)) {
361 throw new IllegalArgumentException("packageName must not be empty");
362 }
363
Hyundo Moone962ed42020-02-16 19:47:41 +0900364 final int uid = Binder.getCallingUid();
365 final int pid = Binder.getCallingPid();
366 final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
Kyunglyul Hyun5a8dedc2019-10-10 14:09:44 +0900367
368 final long token = Binder.clearCallingIdentity();
369 try {
370 synchronized (mLock) {
Sungsoo Lim7065f1b2020-03-24 18:52:42 +0900371 registerManagerLocked(manager, uid, pid, packageName, userId);
Kyunglyul Hyun5161b372020-02-05 18:45:35 +0900372 }
373 } finally {
374 Binder.restoreCallingIdentity(token);
375 }
376 }
377
Hyundo Moone962ed42020-02-16 19:47:41 +0900378 public void unregisterManager(IMediaRouter2Manager manager) {
379 Objects.requireNonNull(manager, "manager must not be null");
Kyunglyul Hyun5161b372020-02-05 18:45:35 +0900380
381 final long token = Binder.clearCallingIdentity();
382 try {
383 synchronized (mLock) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900384 unregisterManagerLocked(manager, false);
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +0900385 }
386 } finally {
387 Binder.restoreCallingIdentity(token);
388 }
389 }
390
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900391 public void setRouteVolumeWithManager(IMediaRouter2Manager manager, int requestId,
392 MediaRoute2Info route, int volume) {
Kyunglyul Hyun5a8dedc2019-10-10 14:09:44 +0900393 Objects.requireNonNull(manager, "manager must not be null");
394 Objects.requireNonNull(route, "route must not be null");
395
396 final long token = Binder.clearCallingIdentity();
397 try {
398 synchronized (mLock) {
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900399 setRouteVolumeWithManagerLocked(requestId, manager, route, volume);
Hyundo Moone962ed42020-02-16 19:47:41 +0900400 }
401 } finally {
402 Binder.restoreCallingIdentity(token);
403 }
404 }
405
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900406 public void requestCreateSessionWithManager(IMediaRouter2Manager manager, int requestId,
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900407 RoutingSessionInfo oldSession, MediaRoute2Info route) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900408 Objects.requireNonNull(manager, "manager must not be null");
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900409 Objects.requireNonNull(oldSession, "oldSession must not be null");
Hyundo Moone962ed42020-02-16 19:47:41 +0900410
411 final long token = Binder.clearCallingIdentity();
412 try {
413 synchronized (mLock) {
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900414 requestCreateSessionWithManagerLocked(requestId, manager, oldSession, route);
Hyundo Moone962ed42020-02-16 19:47:41 +0900415 }
416 } finally {
417 Binder.restoreCallingIdentity(token);
418 }
419 }
420
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900421 public void selectRouteWithManager(IMediaRouter2Manager manager, int requestId,
422 String uniqueSessionId, MediaRoute2Info route) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900423 Objects.requireNonNull(manager, "manager must not be null");
424 if (TextUtils.isEmpty(uniqueSessionId)) {
425 throw new IllegalArgumentException("uniqueSessionId must not be empty");
426 }
427 Objects.requireNonNull(route, "route must not be null");
428
429 final long token = Binder.clearCallingIdentity();
430 try {
431 synchronized (mLock) {
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900432 selectRouteWithManagerLocked(requestId, manager, uniqueSessionId, route);
Hyundo Moone962ed42020-02-16 19:47:41 +0900433 }
434 } finally {
435 Binder.restoreCallingIdentity(token);
436 }
437 }
438
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900439 public void deselectRouteWithManager(IMediaRouter2Manager manager, int requestId,
440 String uniqueSessionId, MediaRoute2Info route) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900441 Objects.requireNonNull(manager, "manager must not be null");
442 if (TextUtils.isEmpty(uniqueSessionId)) {
443 throw new IllegalArgumentException("uniqueSessionId must not be empty");
444 }
445 Objects.requireNonNull(route, "route must not be null");
446
447 final long token = Binder.clearCallingIdentity();
448 try {
449 synchronized (mLock) {
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900450 deselectRouteWithManagerLocked(requestId, manager, uniqueSessionId, route);
Hyundo Moone962ed42020-02-16 19:47:41 +0900451 }
452 } finally {
453 Binder.restoreCallingIdentity(token);
454 }
455 }
456
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900457 public void transferToRouteWithManager(IMediaRouter2Manager manager, int requestId,
458 String uniqueSessionId, MediaRoute2Info route) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900459 Objects.requireNonNull(manager, "manager must not be null");
460 if (TextUtils.isEmpty(uniqueSessionId)) {
461 throw new IllegalArgumentException("uniqueSessionId must not be empty");
462 }
463 Objects.requireNonNull(route, "route must not be null");
464
465 final long token = Binder.clearCallingIdentity();
466 try {
467 synchronized (mLock) {
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900468 transferToRouteWithManagerLocked(requestId, manager, uniqueSessionId, route);
Kyunglyul Hyun5161b372020-02-05 18:45:35 +0900469 }
470 } finally {
471 Binder.restoreCallingIdentity(token);
472 }
473 }
474
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900475 public void setSessionVolumeWithManager(IMediaRouter2Manager manager, int requestId,
476 String uniqueSessionId, int volume) {
Kyunglyul Hyun5161b372020-02-05 18:45:35 +0900477 Objects.requireNonNull(manager, "manager must not be null");
Hyundo Moone962ed42020-02-16 19:47:41 +0900478 if (TextUtils.isEmpty(uniqueSessionId)) {
479 throw new IllegalArgumentException("uniqueSessionId must not be empty");
480 }
Kyunglyul Hyun5161b372020-02-05 18:45:35 +0900481
482 final long token = Binder.clearCallingIdentity();
483 try {
484 synchronized (mLock) {
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900485 setSessionVolumeWithManagerLocked(requestId, manager, uniqueSessionId, volume);
Kyunglyul Hyun5a8dedc2019-10-10 14:09:44 +0900486 }
487 } finally {
488 Binder.restoreCallingIdentity(token);
489 }
490 }
491
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900492 public void releaseSessionWithManager(IMediaRouter2Manager manager, int requestId,
493 String uniqueSessionId) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900494 Objects.requireNonNull(manager, "manager must not be null");
495 if (TextUtils.isEmpty(uniqueSessionId)) {
496 throw new IllegalArgumentException("uniqueSessionId must not be empty");
Kyunglyul Hyunefe43742019-12-31 18:32:28 +0900497 }
Kyunglyul Hyunefe43742019-12-31 18:32:28 +0900498
Kyunglyul Hyunc6583832020-01-17 11:11:46 +0000499 final long token = Binder.clearCallingIdentity();
500 try {
501 synchronized (mLock) {
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900502 releaseSessionWithManagerLocked(requestId, manager, uniqueSessionId);
Kyunglyul Hyunc6583832020-01-17 11:11:46 +0000503 }
504 } finally {
505 Binder.restoreCallingIdentity(token);
506 }
507 }
508
Kyunglyul Hyunef7e88f2020-04-01 22:15:08 +0900509 //TODO(b/136703681): Review this is handling multi-user properly.
Kyunglyul Hyun6c5d7dc2019-04-24 15:57:07 +0900510 void switchUser() {
511 synchronized (mLock) {
512 int userId = ActivityManager.getCurrentUser();
513 if (mCurrentUserId != userId) {
514 final int oldUserId = mCurrentUserId;
515 mCurrentUserId = userId; // do this first
516
517 UserRecord oldUser = mUserRecords.get(oldUserId);
518 if (oldUser != null) {
Kyunglyul Hyun30e2c652019-07-11 16:25:31 +0900519 oldUser.mHandler.sendMessage(
520 obtainMessage(UserHandler::stop, oldUser.mHandler));
Kyunglyul Hyun6c5d7dc2019-04-24 15:57:07 +0900521 disposeUserIfNeededLocked(oldUser); // since no longer current user
522 }
523
524 UserRecord newUser = mUserRecords.get(userId);
525 if (newUser != null) {
Kyunglyul Hyun30e2c652019-07-11 16:25:31 +0900526 newUser.mHandler.sendMessage(
527 obtainMessage(UserHandler::start, newUser.mHandler));
Kyunglyul Hyun6c5d7dc2019-04-24 15:57:07 +0900528 }
529 }
530 }
531 }
532
Hyundo Moone962ed42020-02-16 19:47:41 +0900533 void routerDied(@NonNull RouterRecord routerRecord) {
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +0900534 synchronized (mLock) {
Hyundo Moon56337492020-02-16 16:19:54 +0900535 unregisterRouter2Locked(routerRecord.mRouter, true);
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +0900536 }
537 }
538
Hyundo Moone962ed42020-02-16 19:47:41 +0900539 void managerDied(@NonNull ManagerRecord managerRecord) {
Kyunglyul Hyundafac542019-04-29 18:07:21 +0900540 synchronized (mLock) {
541 unregisterManagerLocked(managerRecord.mManager, true);
542 }
543 }
544
Hyundo Moone962ed42020-02-16 19:47:41 +0900545 ////////////////////////////////////////////////////////////////
546 //// ***Locked methods related to MediaRouter2
547 //// - Should have @NonNull/@Nullable on all arguments
548 ////////////////////////////////////////////////////////////////
549
550 private void registerRouter2Locked(@NonNull IMediaRouter2 router, int uid, int pid,
Sungsoo Lim7065f1b2020-03-24 18:52:42 +0900551 @NonNull String packageName, int userId, boolean hasConfigureWifiDisplayPermission,
552 boolean hasModifyAudioRoutingPermission) {
Hyundo Moon56337492020-02-16 16:19:54 +0900553 final IBinder binder = router.asBinder();
Hyundo Moone962ed42020-02-16 19:47:41 +0900554 if (mAllRouterRecords.get(binder) != null) {
Hyundo Moon369be952020-06-11 17:37:01 +0900555 Slog.w(TAG, "registerRouter2Locked: Same router already exists. packageName="
556 + packageName);
Hyundo Moone962ed42020-02-16 19:47:41 +0900557 return;
Kyunglyul Hyundafac542019-04-29 18:07:21 +0900558 }
Hyundo Moone962ed42020-02-16 19:47:41 +0900559
560 UserRecord userRecord = getOrCreateUserRecordLocked(userId);
Sungsoo Lim7065f1b2020-03-24 18:52:42 +0900561 RouterRecord routerRecord = new RouterRecord(userRecord, router, uid, pid, packageName,
562 hasConfigureWifiDisplayPermission, hasModifyAudioRoutingPermission);
Hyundo Moone962ed42020-02-16 19:47:41 +0900563 try {
564 binder.linkToDeath(routerRecord, 0);
565 } catch (RemoteException ex) {
566 throw new RuntimeException("MediaRouter2 died prematurely.", ex);
567 }
568
569 userRecord.mRouterRecords.add(routerRecord);
570 mAllRouterRecords.put(binder, routerRecord);
571
572 userRecord.mHandler.sendMessage(
Hyundo Moonbc633272020-06-04 18:12:29 +0900573 obtainMessage(UserHandler::notifyRouterRegistered,
Hyundo Moonfa248a72020-05-12 20:05:27 +0900574 userRecord.mHandler, routerRecord));
Kyunglyul Hyundafac542019-04-29 18:07:21 +0900575 }
576
Hyundo Moone962ed42020-02-16 19:47:41 +0900577 private void unregisterRouter2Locked(@NonNull IMediaRouter2 router, boolean died) {
Hyundo Moon56337492020-02-16 16:19:54 +0900578 RouterRecord routerRecord = mAllRouterRecords.remove(router.asBinder());
Hyundo Moone962ed42020-02-16 19:47:41 +0900579 if (routerRecord == null) {
580 Slog.w(TAG, "Ignoring unregistering unknown router2");
581 return;
Kyunglyul Hyundafac542019-04-29 18:07:21 +0900582 }
Hyundo Moone962ed42020-02-16 19:47:41 +0900583
584 UserRecord userRecord = routerRecord.mUserRecord;
585 userRecord.mRouterRecords.remove(routerRecord);
Hyundo Moonac9df102020-06-12 19:36:10 +0900586 routerRecord.mUserRecord.mHandler.sendMessage(
587 obtainMessage(UserHandler::notifyPreferredFeaturesChangedToManagers,
588 routerRecord.mUserRecord.mHandler,
589 routerRecord.mPackageName, /* preferredFeatures=*/ null));
Kyunglyul Hyunef7e88f2020-04-01 22:15:08 +0900590 userRecord.mHandler.sendMessage(
591 obtainMessage(UserHandler::updateDiscoveryPreferenceOnHandler,
592 userRecord.mHandler));
Hyundo Moone962ed42020-02-16 19:47:41 +0900593 routerRecord.dispose();
594 disposeUserIfNeededLocked(userRecord); // since router removed from user
Kyunglyul Hyundafac542019-04-29 18:07:21 +0900595 }
596
Hyundo Moone962ed42020-02-16 19:47:41 +0900597 private void setDiscoveryRequestWithRouter2Locked(@NonNull RouterRecord routerRecord,
598 @NonNull RouteDiscoveryPreference discoveryRequest) {
599 if (routerRecord.mDiscoveryPreference.equals(discoveryRequest)) {
600 return;
Kyunglyul Hyunc7847242019-12-30 17:46:04 +0900601 }
Hyundo Moone962ed42020-02-16 19:47:41 +0900602 routerRecord.mDiscoveryPreference = discoveryRequest;
603 routerRecord.mUserRecord.mHandler.sendMessage(
604 obtainMessage(UserHandler::notifyPreferredFeaturesChangedToManagers,
Hyundo Moonac9df102020-06-12 19:36:10 +0900605 routerRecord.mUserRecord.mHandler,
606 routerRecord.mPackageName,
607 routerRecord.mDiscoveryPreference.getPreferredFeatures()));
Hyundo Moone962ed42020-02-16 19:47:41 +0900608 routerRecord.mUserRecord.mHandler.sendMessage(
Hyundo Moon0fa60e82020-02-14 11:44:45 +0900609 obtainMessage(UserHandler::updateDiscoveryPreferenceOnHandler,
Hyundo Moone962ed42020-02-16 19:47:41 +0900610 routerRecord.mUserRecord.mHandler));
Hyundo Moon63a05402019-12-19 20:13:56 +0900611 }
612
Hyundo Moone962ed42020-02-16 19:47:41 +0900613 private void setRouteVolumeWithRouter2Locked(@NonNull IMediaRouter2 router,
614 @NonNull MediaRoute2Info route, int volume) {
Hyundo Moon56337492020-02-16 16:19:54 +0900615 final IBinder binder = router.asBinder();
616 RouterRecord routerRecord = mAllRouterRecords.get(binder);
Kyunglyul Hyun5a8dedc2019-10-10 14:09:44 +0900617
Hyundo Moon56337492020-02-16 16:19:54 +0900618 if (routerRecord != null) {
619 routerRecord.mUserRecord.mHandler.sendMessage(
Hyundo Moone962ed42020-02-16 19:47:41 +0900620 obtainMessage(UserHandler::setRouteVolumeOnHandler,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900621 routerRecord.mUserRecord.mHandler,
622 DUMMY_REQUEST_ID, route, volume));
Kyunglyul Hyun5a8dedc2019-10-10 14:09:44 +0900623 }
624 }
625
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900626 private void requestCreateSessionWithRouter2Locked(int requestId, long managerRequestId,
627 @NonNull IMediaRouter2 router, @NonNull RoutingSessionInfo oldSession,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900628 @NonNull MediaRoute2Info route, @Nullable Bundle sessionHints) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900629 final IBinder binder = router.asBinder();
630 final RouterRecord routerRecord = mAllRouterRecords.get(binder);
631
632 if (routerRecord == null) {
633 return;
634 }
635
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900636 if (managerRequestId != MediaRoute2ProviderService.REQUEST_ID_NONE) {
637 ManagerRecord manager = routerRecord.mUserRecord.mHandler.findManagerWithId(
638 toRequesterId(managerRequestId));
639 if (manager == null || manager.mLastSessionCreationRequest == null) {
640 Slog.w(TAG, "requestCreateSessionWithRouter2Locked: "
641 + "Ignoring unknown request.");
642 routerRecord.mUserRecord.mHandler.notifySessionCreationFailedToRouter(
643 routerRecord, requestId);
644 return;
645 }
646 if (!TextUtils.equals(manager.mLastSessionCreationRequest.mOldSession.getId(),
647 oldSession.getId())) {
648 Slog.w(TAG, "requestCreateSessionWithRouter2Locked: "
649 + "Ignoring unmatched routing session.");
650 routerRecord.mUserRecord.mHandler.notifySessionCreationFailedToRouter(
651 routerRecord, requestId);
652 return;
653 }
654 if (!TextUtils.equals(manager.mLastSessionCreationRequest.mRoute.getId(),
655 route.getId())) {
656 // When media router has no permission
657 if (!routerRecord.mHasModifyAudioRoutingPermission
658 && manager.mLastSessionCreationRequest.mRoute.isSystemRoute()
659 && route.isSystemRoute()) {
660 route = manager.mLastSessionCreationRequest.mRoute;
661 } else {
662 Slog.w(TAG, "requestCreateSessionWithRouter2Locked: "
663 + "Ignoring unmatched route.");
664 routerRecord.mUserRecord.mHandler.notifySessionCreationFailedToRouter(
665 routerRecord, requestId);
666 return;
667 }
668 }
669 manager.mLastSessionCreationRequest = null;
670 } else {
671 if (route.isSystemRoute() && !routerRecord.mHasModifyAudioRoutingPermission
672 && !TextUtils.equals(route.getId(),
673 routerRecord.mUserRecord.mHandler.mSystemProvider.getDefaultRoute().getId())) {
674 Slog.w(TAG, "MODIFY_AUDIO_ROUTING permission is required to transfer to"
675 + route);
676 routerRecord.mUserRecord.mHandler.notifySessionCreationFailedToRouter(
677 routerRecord, requestId);
678 return;
679 }
Hyundo Moonfa3d0ef2020-04-13 00:27:44 +0900680 }
681
Hyundo Moone962ed42020-02-16 19:47:41 +0900682 long uniqueRequestId = toUniqueRequestId(routerRecord.mRouterId, requestId);
683 routerRecord.mUserRecord.mHandler.sendMessage(
Kyunglyul Hyunf0eb51b2020-04-14 19:56:16 +0900684 obtainMessage(UserHandler::requestCreateSessionWithRouter2OnHandler,
Hyundo Moone962ed42020-02-16 19:47:41 +0900685 routerRecord.mUserRecord.mHandler,
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900686 uniqueRequestId, managerRequestId, routerRecord, oldSession, route,
Hyundo Moon7c2059c2020-02-27 19:01:52 +0900687 sessionHints));
Hyundo Moone962ed42020-02-16 19:47:41 +0900688 }
689
690 private void selectRouteWithRouter2Locked(@NonNull IMediaRouter2 router,
691 @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
692 final IBinder binder = router.asBinder();
693 final RouterRecord routerRecord = mAllRouterRecords.get(binder);
694
695 if (routerRecord == null) {
696 return;
697 }
698
699 routerRecord.mUserRecord.mHandler.sendMessage(
700 obtainMessage(UserHandler::selectRouteOnHandler,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900701 routerRecord.mUserRecord.mHandler,
702 DUMMY_REQUEST_ID, routerRecord, uniqueSessionId, route));
Hyundo Moone962ed42020-02-16 19:47:41 +0900703 }
704
705 private void deselectRouteWithRouter2Locked(@NonNull IMediaRouter2 router,
706 @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
707 final IBinder binder = router.asBinder();
708 final RouterRecord routerRecord = mAllRouterRecords.get(binder);
709
710 if (routerRecord == null) {
711 return;
712 }
713
714 routerRecord.mUserRecord.mHandler.sendMessage(
715 obtainMessage(UserHandler::deselectRouteOnHandler,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900716 routerRecord.mUserRecord.mHandler,
717 DUMMY_REQUEST_ID, routerRecord, uniqueSessionId, route));
Hyundo Moone962ed42020-02-16 19:47:41 +0900718 }
719
720 private void transferToRouteWithRouter2Locked(@NonNull IMediaRouter2 router,
721 @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
722 final IBinder binder = router.asBinder();
723 final RouterRecord routerRecord = mAllRouterRecords.get(binder);
724
725 if (routerRecord == null) {
726 return;
727 }
728
Sungsoo Limc27785a2020-03-27 16:57:47 +0900729 String defaultRouteId =
730 routerRecord.mUserRecord.mHandler.mSystemProvider.getDefaultRoute().getId();
731 if (route.isSystemRoute() && !routerRecord.mHasModifyAudioRoutingPermission
732 && !TextUtils.equals(route.getId(), defaultRouteId)) {
733 routerRecord.mUserRecord.mHandler.sendMessage(
734 obtainMessage(UserHandler::notifySessionCreationFailedToRouter,
735 routerRecord.mUserRecord.mHandler,
736 routerRecord, toOriginalRequestId(DUMMY_REQUEST_ID)));
737 } else {
738 routerRecord.mUserRecord.mHandler.sendMessage(
739 obtainMessage(UserHandler::transferToRouteOnHandler,
740 routerRecord.mUserRecord.mHandler,
741 DUMMY_REQUEST_ID, routerRecord, uniqueSessionId, route));
742 }
Hyundo Moone962ed42020-02-16 19:47:41 +0900743 }
744
745 private void setSessionVolumeWithRouter2Locked(@NonNull IMediaRouter2 router,
746 @NonNull String uniqueSessionId, int volume) {
Hyundo Moon56337492020-02-16 16:19:54 +0900747 final IBinder binder = router.asBinder();
748 RouterRecord routerRecord = mAllRouterRecords.get(binder);
Kyunglyul Hyun5161b372020-02-05 18:45:35 +0900749
Hyundo Moone962ed42020-02-16 19:47:41 +0900750 if (routerRecord == null) {
751 return;
Kyunglyul Hyun5161b372020-02-05 18:45:35 +0900752 }
Hyundo Moone962ed42020-02-16 19:47:41 +0900753
754 routerRecord.mUserRecord.mHandler.sendMessage(
755 obtainMessage(UserHandler::setSessionVolumeOnHandler,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900756 routerRecord.mUserRecord.mHandler,
757 DUMMY_REQUEST_ID, uniqueSessionId, volume));
Kyunglyul Hyun5161b372020-02-05 18:45:35 +0900758 }
759
Hyundo Moone962ed42020-02-16 19:47:41 +0900760 private void releaseSessionWithRouter2Locked(@NonNull IMediaRouter2 router,
761 @NonNull String uniqueSessionId) {
762 final IBinder binder = router.asBinder();
763 final RouterRecord routerRecord = mAllRouterRecords.get(binder);
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +0900764
Hyundo Moone962ed42020-02-16 19:47:41 +0900765 if (routerRecord == null) {
766 return;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +0900767 }
Hyundo Moone962ed42020-02-16 19:47:41 +0900768
769 routerRecord.mUserRecord.mHandler.sendMessage(
770 obtainMessage(UserHandler::releaseSessionOnHandler,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900771 routerRecord.mUserRecord.mHandler,
772 DUMMY_REQUEST_ID, routerRecord, uniqueSessionId));
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +0900773 }
774
Hyundo Moone962ed42020-02-16 19:47:41 +0900775 ////////////////////////////////////////////////////////////
776 //// ***Locked methods related to MediaRouter2Manager
777 //// - Should have @NonNull/@Nullable on all arguments
778 ////////////////////////////////////////////////////////////
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +0900779
Hyundo Moone962ed42020-02-16 19:47:41 +0900780 private List<RoutingSessionInfo> getActiveSessionsLocked(
781 @NonNull IMediaRouter2Manager manager) {
Kyunglyul Hyunefe43742019-12-31 18:32:28 +0900782 final IBinder binder = manager.asBinder();
783 ManagerRecord managerRecord = mAllManagerRecords.get(binder);
784
785 if (managerRecord == null) {
Kyunglyul Hyunc6583832020-01-17 11:11:46 +0000786 Slog.w(TAG, "getActiveSessionLocked: Ignoring unknown manager");
Kyunglyul Hyunefe43742019-12-31 18:32:28 +0900787 return Collections.emptyList();
788 }
789
Hyundo Moonf829e6f2020-01-11 19:31:35 +0900790 List<RoutingSessionInfo> sessionInfos = new ArrayList<>();
Sungsoo Limddf140d2020-03-25 08:53:55 +0900791 for (MediaRoute2Provider provider : managerRecord.mUserRecord.mHandler.mRouteProviders) {
Kyunglyul Hyunefe43742019-12-31 18:32:28 +0900792 sessionInfos.addAll(provider.getSessionInfos());
793 }
794 return sessionInfos;
795 }
796
Hyundo Moone962ed42020-02-16 19:47:41 +0900797 private void registerManagerLocked(@NonNull IMediaRouter2Manager manager,
Sungsoo Lim7065f1b2020-03-24 18:52:42 +0900798 int uid, int pid, @NonNull String packageName, int userId) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900799 final IBinder binder = manager.asBinder();
800 ManagerRecord managerRecord = mAllManagerRecords.get(binder);
801
802 if (managerRecord != null) {
Hyundo Moon369be952020-06-11 17:37:01 +0900803 Slog.w(TAG, "registerManagerLocked: Same manager already exists. packageName="
804 + packageName);
Hyundo Moone962ed42020-02-16 19:47:41 +0900805 return;
806 }
807
808 UserRecord userRecord = getOrCreateUserRecordLocked(userId);
Sungsoo Lim7065f1b2020-03-24 18:52:42 +0900809 managerRecord = new ManagerRecord(userRecord, manager, uid, pid, packageName);
Hyundo Moone962ed42020-02-16 19:47:41 +0900810 try {
811 binder.linkToDeath(managerRecord, 0);
812 } catch (RemoteException ex) {
813 throw new RuntimeException("Media router manager died prematurely.", ex);
814 }
815
816 userRecord.mManagerRecords.add(managerRecord);
817 mAllManagerRecords.put(binder, managerRecord);
818
819 userRecord.mHandler.sendMessage(obtainMessage(UserHandler::notifyRoutesToManager,
820 userRecord.mHandler, manager));
821
822 for (RouterRecord routerRecord : userRecord.mRouterRecords) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900823 // TODO: UserRecord <-> routerRecord, why do they reference each other?
824 // How about removing mUserRecord from routerRecord?
825 routerRecord.mUserRecord.mHandler.sendMessage(
Hyundo Moon38d06df2020-05-20 14:24:06 +0900826 obtainMessage(UserHandler::notifyPreferredFeaturesChangedToManager,
827 routerRecord.mUserRecord.mHandler, routerRecord, manager));
Hyundo Moone962ed42020-02-16 19:47:41 +0900828 }
829 }
830
831 private void unregisterManagerLocked(@NonNull IMediaRouter2Manager manager, boolean died) {
832 ManagerRecord managerRecord = mAllManagerRecords.remove(manager.asBinder());
833 if (managerRecord == null) {
834 return;
835 }
836 UserRecord userRecord = managerRecord.mUserRecord;
837 userRecord.mManagerRecords.remove(managerRecord);
838 managerRecord.dispose();
839 disposeUserIfNeededLocked(userRecord); // since manager removed from user
840 }
841
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900842 private void setRouteVolumeWithManagerLocked(int requestId,
843 @NonNull IMediaRouter2Manager manager,
844 @NonNull MediaRoute2Info route, int volume) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900845 final IBinder binder = manager.asBinder();
846 ManagerRecord managerRecord = mAllManagerRecords.get(binder);
847
848 if (managerRecord == null) {
849 return;
850 }
Hyundo Moon0fa60e82020-02-14 11:44:45 +0900851
852 long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
Hyundo Moone962ed42020-02-16 19:47:41 +0900853 managerRecord.mUserRecord.mHandler.sendMessage(
854 obtainMessage(UserHandler::setRouteVolumeOnHandler,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900855 managerRecord.mUserRecord.mHandler,
856 uniqueRequestId, route, volume));
Hyundo Moone962ed42020-02-16 19:47:41 +0900857 }
858
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900859 private void requestCreateSessionWithManagerLocked(int requestId,
860 @NonNull IMediaRouter2Manager manager,
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900861 @NonNull RoutingSessionInfo oldSession, @NonNull MediaRoute2Info route) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900862 ManagerRecord managerRecord = mAllManagerRecords.get(manager.asBinder());
Sungsoo Lim7065f1b2020-03-24 18:52:42 +0900863 if (managerRecord == null) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900864 return;
865 }
866
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900867 String packageName = oldSession.getClientPackageName();
868
Hyundo Moone962ed42020-02-16 19:47:41 +0900869 RouterRecord routerRecord = managerRecord.mUserRecord.findRouterRecordLocked(packageName);
870 if (routerRecord == null) {
Hyundo Moon369be952020-06-11 17:37:01 +0900871 Slog.w(TAG, "requestCreateSessionWithManagerLocked: Ignoring session creation for "
872 + "unknown router.");
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900873 try {
874 managerRecord.mManager.notifyRequestFailed(requestId, REASON_UNKNOWN_ERROR);
875 } catch (RemoteException ex) {
876 Slog.w(TAG, "requestCreateSessionWithManagerLocked: Failed to notify failure. "
877 + "Manager probably died.");
878 }
Hyundo Moone962ed42020-02-16 19:47:41 +0900879 return;
880 }
881
882 long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900883 if (managerRecord.mLastSessionCreationRequest != null) {
884 managerRecord.mUserRecord.mHandler.notifyRequestFailedToManager(
885 managerRecord.mManager,
886 toOriginalRequestId(managerRecord.mLastSessionCreationRequest
887 .mManagerRequestId),
888 REASON_UNKNOWN_ERROR);
889 managerRecord.mLastSessionCreationRequest = null;
890 }
891 managerRecord.mLastSessionCreationRequest = new SessionCreationRequest(routerRecord,
892 MediaRoute2ProviderService.REQUEST_ID_NONE, uniqueRequestId,
893 oldSession, route);
Kyunglyul Hyunf0eb51b2020-04-14 19:56:16 +0900894
895 // Before requesting to the provider, get session hints from the media router.
896 // As a return, media router will request to create a session.
Hyundo Moone962ed42020-02-16 19:47:41 +0900897 routerRecord.mUserRecord.mHandler.sendMessage(
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900898 obtainMessage(UserHandler::requestRouterCreateSessionOnHandler,
Hyundo Moone962ed42020-02-16 19:47:41 +0900899 routerRecord.mUserRecord.mHandler,
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900900 uniqueRequestId, routerRecord, managerRecord, oldSession, route));
Hyundo Moone962ed42020-02-16 19:47:41 +0900901 }
902
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900903 private void selectRouteWithManagerLocked(int requestId, @NonNull IMediaRouter2Manager manager,
904 @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900905 final IBinder binder = manager.asBinder();
906 ManagerRecord managerRecord = mAllManagerRecords.get(binder);
907
908 if (managerRecord == null) {
909 return;
910 }
911
Kyunglyul Hyuna69280b2020-04-03 15:15:09 +0900912 // Can be null if the session is system's or RCN.
Hyundo Moone962ed42020-02-16 19:47:41 +0900913 RouterRecord routerRecord = managerRecord.mUserRecord.mHandler
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900914 .findRouterWithSessionLocked(uniqueSessionId);
Hyundo Moone962ed42020-02-16 19:47:41 +0900915
Hyundo Moon0fa60e82020-02-14 11:44:45 +0900916 long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
Hyundo Moone962ed42020-02-16 19:47:41 +0900917 managerRecord.mUserRecord.mHandler.sendMessage(
918 obtainMessage(UserHandler::selectRouteOnHandler,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900919 managerRecord.mUserRecord.mHandler,
920 uniqueRequestId, routerRecord, uniqueSessionId, route));
Hyundo Moone962ed42020-02-16 19:47:41 +0900921 }
922
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900923 private void deselectRouteWithManagerLocked(int requestId,
924 @NonNull IMediaRouter2Manager manager,
925 @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900926 final IBinder binder = manager.asBinder();
927 ManagerRecord managerRecord = mAllManagerRecords.get(binder);
928
929 if (managerRecord == null) {
930 return;
931 }
932
Kyunglyul Hyuna69280b2020-04-03 15:15:09 +0900933 // Can be null if the session is system's or RCN.
Hyundo Moone962ed42020-02-16 19:47:41 +0900934 RouterRecord routerRecord = managerRecord.mUserRecord.mHandler
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900935 .findRouterWithSessionLocked(uniqueSessionId);
Hyundo Moone962ed42020-02-16 19:47:41 +0900936
Hyundo Moon0fa60e82020-02-14 11:44:45 +0900937 long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
Hyundo Moone962ed42020-02-16 19:47:41 +0900938 managerRecord.mUserRecord.mHandler.sendMessage(
939 obtainMessage(UserHandler::deselectRouteOnHandler,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900940 managerRecord.mUserRecord.mHandler,
941 uniqueRequestId, routerRecord, uniqueSessionId, route));
Hyundo Moone962ed42020-02-16 19:47:41 +0900942 }
943
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900944 private void transferToRouteWithManagerLocked(int requestId,
945 @NonNull IMediaRouter2Manager manager,
946 @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900947 final IBinder binder = manager.asBinder();
948 ManagerRecord managerRecord = mAllManagerRecords.get(binder);
949
950 if (managerRecord == null) {
951 return;
952 }
953
Kyunglyul Hyuna69280b2020-04-03 15:15:09 +0900954 // Can be null if the session is system's or RCN.
Hyundo Moone962ed42020-02-16 19:47:41 +0900955 RouterRecord routerRecord = managerRecord.mUserRecord.mHandler
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900956 .findRouterWithSessionLocked(uniqueSessionId);
Hyundo Moone962ed42020-02-16 19:47:41 +0900957
Hyundo Moon0fa60e82020-02-14 11:44:45 +0900958 long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
Hyundo Moone962ed42020-02-16 19:47:41 +0900959 managerRecord.mUserRecord.mHandler.sendMessage(
960 obtainMessage(UserHandler::transferToRouteOnHandler,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900961 managerRecord.mUserRecord.mHandler,
962 uniqueRequestId, routerRecord, uniqueSessionId, route));
Hyundo Moone962ed42020-02-16 19:47:41 +0900963 }
964
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900965 private void setSessionVolumeWithManagerLocked(int requestId,
966 @NonNull IMediaRouter2Manager manager,
967 @NonNull String uniqueSessionId, int volume) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900968 final IBinder binder = manager.asBinder();
969 ManagerRecord managerRecord = mAllManagerRecords.get(binder);
970
971 if (managerRecord == null) {
972 return;
973 }
974
Hyundo Moon0fa60e82020-02-14 11:44:45 +0900975 long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
Hyundo Moone962ed42020-02-16 19:47:41 +0900976 managerRecord.mUserRecord.mHandler.sendMessage(
977 obtainMessage(UserHandler::setSessionVolumeOnHandler,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900978 managerRecord.mUserRecord.mHandler,
979 uniqueRequestId, uniqueSessionId, volume));
Hyundo Moone962ed42020-02-16 19:47:41 +0900980 }
981
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900982 private void releaseSessionWithManagerLocked(int requestId,
983 @NonNull IMediaRouter2Manager manager,
984 @NonNull String uniqueSessionId) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900985 final IBinder binder = manager.asBinder();
986 ManagerRecord managerRecord = mAllManagerRecords.get(binder);
987
988 if (managerRecord == null) {
989 return;
990 }
991
992 RouterRecord routerRecord = managerRecord.mUserRecord.mHandler
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900993 .findRouterWithSessionLocked(uniqueSessionId);
Hyundo Moone962ed42020-02-16 19:47:41 +0900994
Hyundo Moon0fa60e82020-02-14 11:44:45 +0900995 long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
Hyundo Moone962ed42020-02-16 19:47:41 +0900996 managerRecord.mUserRecord.mHandler.sendMessage(
997 obtainMessage(UserHandler::releaseSessionOnHandler,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900998 managerRecord.mUserRecord.mHandler,
999 uniqueRequestId, routerRecord, uniqueSessionId));
Hyundo Moone962ed42020-02-16 19:47:41 +09001000 }
1001
1002 ////////////////////////////////////////////////////////////
1003 //// ***Locked methods used by both router2 and manager
1004 //// - Should have @NonNull/@Nullable on all arguments
1005 ////////////////////////////////////////////////////////////
1006
Sungsoo Limdfafaf72020-01-07 13:04:05 +09001007 private UserRecord getOrCreateUserRecordLocked(int userId) {
1008 UserRecord userRecord = mUserRecords.get(userId);
1009 if (userRecord == null) {
1010 userRecord = new UserRecord(userId);
1011 mUserRecords.put(userId, userRecord);
Hyundo Moonaa803752020-06-17 23:02:49 +09001012 userRecord.init();
Sungsoo Limdfafaf72020-01-07 13:04:05 +09001013 if (userId == mCurrentUserId) {
1014 userRecord.mHandler.sendMessage(
1015 obtainMessage(UserHandler::start, userRecord.mHandler));
1016 }
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001017 }
Sungsoo Limdfafaf72020-01-07 13:04:05 +09001018 return userRecord;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001019 }
1020
Hyundo Moone962ed42020-02-16 19:47:41 +09001021 private void disposeUserIfNeededLocked(@NonNull UserRecord userRecord) {
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001022 // If there are no records left and the user is no longer current then go ahead
1023 // and purge the user record and all of its associated state. If the user is current
1024 // then leave it alone since we might be connected to a route or want to query
1025 // the same route information again soon.
1026 if (userRecord.mUserId != mCurrentUserId
Hyundo Moon56337492020-02-16 16:19:54 +09001027 && userRecord.mRouterRecords.isEmpty()
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001028 && userRecord.mManagerRecords.isEmpty()) {
1029 if (DEBUG) {
1030 Slog.d(TAG, userRecord + ": Disposed");
1031 }
1032 mUserRecords.remove(userRecord.mUserId);
1033 // Note: User already stopped (by switchUser) so no need to send stop message here.
1034 }
1035 }
1036
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001037 static long toUniqueRequestId(int requesterId, int originalRequestId) {
1038 return ((long) requesterId << 32) | originalRequestId;
Kyunglyul Hyunc7847242019-12-30 17:46:04 +09001039 }
1040
Hyundo Moon7c2059c2020-02-27 19:01:52 +09001041 static int toRequesterId(long uniqueRequestId) {
Kyunglyul Hyunc7847242019-12-30 17:46:04 +09001042 return (int) (uniqueRequestId >> 32);
1043 }
1044
Hyundo Moon56337492020-02-16 16:19:54 +09001045 static int toOriginalRequestId(long uniqueRequestId) {
Kyunglyul Hyunc7847242019-12-30 17:46:04 +09001046 return (int) uniqueRequestId;
1047 }
1048
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001049 final class UserRecord {
1050 public final int mUserId;
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001051 //TODO: make records private for thread-safety
Hyundo Moon56337492020-02-16 16:19:54 +09001052 final ArrayList<RouterRecord> mRouterRecords = new ArrayList<>();
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001053 final ArrayList<ManagerRecord> mManagerRecords = new ArrayList<>();
Kyunglyul Hyun1866d8a2020-01-31 11:56:34 +09001054 RouteDiscoveryPreference mCompositeDiscoveryPreference = RouteDiscoveryPreference.EMPTY;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001055 final UserHandler mHandler;
1056
1057 UserRecord(int userId) {
1058 mUserId = userId;
1059 mHandler = new UserHandler(MediaRouter2ServiceImpl.this, this);
1060 }
Kyunglyul Hyun13bc1052019-05-31 17:00:36 +09001061
Hyundo Moonaa803752020-06-17 23:02:49 +09001062 void init() {
1063 mHandler.init();
1064 }
1065
Hyundo Moon0f78fc62020-06-01 14:50:32 +09001066 // TODO: This assumes that only one router exists in a package.
1067 // Do this in Android S or later.
Hyundo Moon56337492020-02-16 16:19:54 +09001068 RouterRecord findRouterRecordLocked(String packageName) {
1069 for (RouterRecord routerRecord : mRouterRecords) {
1070 if (TextUtils.equals(routerRecord.mPackageName, packageName)) {
1071 return routerRecord;
Kyunglyul Hyuna0d47412019-07-01 11:14:24 +09001072 }
Kyunglyul Hyun13bc1052019-05-31 17:00:36 +09001073 }
1074 return null;
1075 }
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001076 }
1077
Hyundo Moon56337492020-02-16 16:19:54 +09001078 final class RouterRecord implements IBinder.DeathRecipient {
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001079 public final UserRecord mUserRecord;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001080 public final String mPackageName;
Hyundo Moon4140fee2019-11-08 14:47:50 +09001081 public final List<Integer> mSelectRouteSequenceNumbers;
Hyundo Moon56337492020-02-16 16:19:54 +09001082 public final IMediaRouter2 mRouter;
Kyunglyul Hyun86576712019-11-21 18:31:46 +09001083 public final int mUid;
1084 public final int mPid;
Sungsoo Lim7065f1b2020-03-24 18:52:42 +09001085 public final boolean mHasConfigureWifiDisplayPermission;
1086 public final boolean mHasModifyAudioRoutingPermission;
Hyundo Moon56337492020-02-16 16:19:54 +09001087 public final int mRouterId;
Kyunglyul Hyunf7d5e042019-11-11 13:56:28 +09001088
Kyunglyul Hyun616096e2020-01-09 16:15:03 +09001089 public RouteDiscoveryPreference mDiscoveryPreference;
Kyunglyul Hyun13bc1052019-05-31 17:00:36 +09001090 public MediaRoute2Info mSelectedRoute;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001091
Sungsoo Lim7065f1b2020-03-24 18:52:42 +09001092 RouterRecord(UserRecord userRecord, IMediaRouter2 router, int uid, int pid,
1093 String packageName, boolean hasConfigureWifiDisplayPermission,
1094 boolean hasModifyAudioRoutingPermission) {
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001095 mUserRecord = userRecord;
Kyunglyul Hyun2f43fd62019-09-16 18:47:52 +09001096 mPackageName = packageName;
Hyundo Moon4140fee2019-11-08 14:47:50 +09001097 mSelectRouteSequenceNumbers = new ArrayList<>();
Kyunglyul Hyun616096e2020-01-09 16:15:03 +09001098 mDiscoveryPreference = RouteDiscoveryPreference.EMPTY;
Hyundo Moon56337492020-02-16 16:19:54 +09001099 mRouter = router;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001100 mUid = uid;
1101 mPid = pid;
Sungsoo Lim7065f1b2020-03-24 18:52:42 +09001102 mHasConfigureWifiDisplayPermission = hasConfigureWifiDisplayPermission;
1103 mHasModifyAudioRoutingPermission = hasModifyAudioRoutingPermission;
Hyundo Moon56337492020-02-16 16:19:54 +09001104 mRouterId = mNextRouterOrManagerId.getAndIncrement();
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001105 }
1106
1107 public void dispose() {
Hyundo Moon56337492020-02-16 16:19:54 +09001108 mRouter.asBinder().unlinkToDeath(this, 0);
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001109 }
1110
1111 @Override
1112 public void binderDied() {
Hyundo Moon56337492020-02-16 16:19:54 +09001113 routerDied(this);
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001114 }
Kyunglyul Hyundafac542019-04-29 18:07:21 +09001115 }
1116
1117 final class ManagerRecord implements IBinder.DeathRecipient {
1118 public final UserRecord mUserRecord;
1119 public final IMediaRouter2Manager mManager;
1120 public final int mUid;
1121 public final int mPid;
1122 public final String mPackageName;
Hyundo Moon56337492020-02-16 16:19:54 +09001123 public final int mManagerId;
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +09001124 public SessionCreationRequest mLastSessionCreationRequest;
Kyunglyul Hyundafac542019-04-29 18:07:21 +09001125
1126 ManagerRecord(UserRecord userRecord, IMediaRouter2Manager manager,
Sungsoo Lim7065f1b2020-03-24 18:52:42 +09001127 int uid, int pid, String packageName) {
Kyunglyul Hyundafac542019-04-29 18:07:21 +09001128 mUserRecord = userRecord;
1129 mManager = manager;
1130 mUid = uid;
1131 mPid = pid;
1132 mPackageName = packageName;
Hyundo Moon56337492020-02-16 16:19:54 +09001133 mManagerId = mNextRouterOrManagerId.getAndIncrement();
Kyunglyul Hyundafac542019-04-29 18:07:21 +09001134 }
1135
1136 public void dispose() {
1137 mManager.asBinder().unlinkToDeath(this, 0);
1138 }
1139
1140 @Override
1141 public void binderDied() {
1142 managerDied(this);
1143 }
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001144
1145 public void dump(PrintWriter pw, String prefix) {
1146 pw.println(prefix + this);
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001147 }
1148
1149 @Override
1150 public String toString() {
Kyunglyul Hyundafac542019-04-29 18:07:21 +09001151 return "Manager " + mPackageName + " (pid " + mPid + ")";
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001152 }
1153 }
1154
1155 static final class UserHandler extends Handler implements
1156 MediaRoute2ProviderWatcher.Callback,
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +00001157 MediaRoute2Provider.Callback {
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001158
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001159 private final WeakReference<MediaRouter2ServiceImpl> mServiceRef;
1160 private final UserRecord mUserRecord;
1161 private final MediaRoute2ProviderWatcher mWatcher;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001162
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +00001163 private final SystemMediaRoute2Provider mSystemProvider;
Sungsoo Limddf140d2020-03-25 08:53:55 +09001164 private final ArrayList<MediaRoute2Provider> mRouteProviders =
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001165 new ArrayList<>();
Hyundo Moon63a05402019-12-19 20:13:56 +09001166
1167 private final List<MediaRoute2ProviderInfo> mLastProviderInfos = new ArrayList<>();
1168 private final CopyOnWriteArrayList<SessionCreationRequest> mSessionCreationRequests =
1169 new CopyOnWriteArrayList<>();
Hyundo Moon56337492020-02-16 16:19:54 +09001170 private final Map<String, RouterRecord> mSessionToRouterMap = new ArrayMap<>();
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001171
1172 private boolean mRunning;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001173
Hyundo Moonaa803752020-06-17 23:02:49 +09001174 // TODO: (In Android S+) Pull out SystemMediaRoute2Provider out of UserHandler.
Hyundo Moone962ed42020-02-16 19:47:41 +09001175 UserHandler(@NonNull MediaRouter2ServiceImpl service, @NonNull UserRecord userRecord) {
Kyunglyul Hyun6c5d7dc2019-04-24 15:57:07 +09001176 super(Looper.getMainLooper(), null, true);
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001177 mServiceRef = new WeakReference<>(service);
1178 mUserRecord = userRecord;
Hyundo Moonaa803752020-06-17 23:02:49 +09001179 mSystemProvider = new SystemMediaRoute2Provider(service.mContext);
Sungsoo Limddf140d2020-03-25 08:53:55 +09001180 mRouteProviders.add(mSystemProvider);
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001181 mWatcher = new MediaRoute2ProviderWatcher(service.mContext, this,
1182 this, mUserRecord.mUserId);
1183 }
1184
Hyundo Moonaa803752020-06-17 23:02:49 +09001185 void init() {
1186 mSystemProvider.setCallback(this);
1187 }
1188
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001189 private void start() {
1190 if (!mRunning) {
1191 mRunning = true;
1192 mWatcher.start();
1193 }
1194 }
1195
1196 private void stop() {
1197 if (mRunning) {
1198 mRunning = false;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001199 mWatcher.stop(); // also stops all providers
1200 }
1201 }
1202
1203 @Override
Hyundo Moone962ed42020-02-16 19:47:41 +09001204 public void onAddProviderService(@NonNull MediaRoute2ProviderServiceProxy proxy) {
Hyundo Moon56337492020-02-16 16:19:54 +09001205 proxy.setCallback(this);
Sungsoo Limddf140d2020-03-25 08:53:55 +09001206 mRouteProviders.add(proxy);
Hyundo Moon56337492020-02-16 16:19:54 +09001207 proxy.updateDiscoveryPreference(mUserRecord.mCompositeDiscoveryPreference);
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001208 }
1209
1210 @Override
Hyundo Moone962ed42020-02-16 19:47:41 +09001211 public void onRemoveProviderService(@NonNull MediaRoute2ProviderServiceProxy proxy) {
Sungsoo Limddf140d2020-03-25 08:53:55 +09001212 mRouteProviders.remove(proxy);
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001213 }
1214
1215 @Override
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +00001216 public void onProviderStateChanged(@NonNull MediaRoute2Provider provider) {
Hyundo Moonca9db782020-01-01 18:31:15 +09001217 sendMessage(PooledLambda.obtainMessage(UserHandler::onProviderStateChangedOnHandler,
1218 this, provider));
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001219 }
1220
Kyunglyul Hyunf7d5e042019-11-11 13:56:28 +09001221 @Override
Hyundo Moon63a05402019-12-19 20:13:56 +09001222 public void onSessionCreated(@NonNull MediaRoute2Provider provider,
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001223 long uniqueRequestId, @NonNull RoutingSessionInfo sessionInfo) {
Hyundo Moonca9db782020-01-01 18:31:15 +09001224 sendMessage(PooledLambda.obtainMessage(UserHandler::onSessionCreatedOnHandler,
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001225 this, provider, uniqueRequestId, sessionInfo));
Hyundo Moon63a05402019-12-19 20:13:56 +09001226 }
1227
Hyundo Moon6e30f1b2020-01-13 19:50:27 +09001228 @Override
1229 public void onSessionUpdated(@NonNull MediaRoute2Provider provider,
Hyundo Moonf829e6f2020-01-11 19:31:35 +09001230 @NonNull RoutingSessionInfo sessionInfo) {
Hyundo Moonca9db782020-01-01 18:31:15 +09001231 sendMessage(PooledLambda.obtainMessage(UserHandler::onSessionInfoChangedOnHandler,
1232 this, provider, sessionInfo));
1233 }
1234
1235 @Override
Hyundo Moone962ed42020-02-16 19:47:41 +09001236 public void onSessionReleased(@NonNull MediaRoute2Provider provider,
1237 @NonNull RoutingSessionInfo sessionInfo) {
Hyundo Moonca9db782020-01-01 18:31:15 +09001238 sendMessage(PooledLambda.obtainMessage(UserHandler::onSessionReleasedOnHandler,
Hyundo Moon0a926572019-12-28 15:01:21 +09001239 this, provider, sessionInfo));
1240 }
1241
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001242 @Override
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001243 public void onRequestFailed(@NonNull MediaRoute2Provider provider, long uniqueRequestId,
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001244 int reason) {
1245 sendMessage(PooledLambda.obtainMessage(UserHandler::onRequestFailedOnHandler,
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001246 this, provider, uniqueRequestId, reason));
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001247 }
1248
Kyunglyul Hyunc6583832020-01-17 11:11:46 +00001249 @Nullable
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +09001250 public RouterRecord findRouterWithSessionLocked(@NonNull String uniqueSessionId) {
Hyundo Moone962ed42020-02-16 19:47:41 +09001251 return mSessionToRouterMap.get(uniqueSessionId);
Kyunglyul Hyunc6583832020-01-17 11:11:46 +00001252 }
1253
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +09001254 @Nullable
1255 public ManagerRecord findManagerWithId(int managerId) {
1256 for (ManagerRecord manager : getManagerRecords()) {
1257 if (manager.mManagerId == managerId) {
1258 return manager;
1259 }
1260 }
1261 return null;
1262 }
1263
Hyundo Moone962ed42020-02-16 19:47:41 +09001264 private void onProviderStateChangedOnHandler(@NonNull MediaRoute2Provider provider) {
Sungsoo Limddf140d2020-03-25 08:53:55 +09001265 int providerInfoIndex = getLastProviderInfoIndex(provider.getUniqueId());
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001266 MediaRoute2ProviderInfo currentInfo = provider.getProviderInfo();
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001267 MediaRoute2ProviderInfo prevInfo =
Sungsoo Limddf140d2020-03-25 08:53:55 +09001268 (providerInfoIndex < 0) ? null : mLastProviderInfos.get(providerInfoIndex);
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001269 if (Objects.equals(prevInfo, currentInfo)) return;
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001270
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001271 List<MediaRoute2Info> addedRoutes = new ArrayList<>();
1272 List<MediaRoute2Info> removedRoutes = new ArrayList<>();
1273 List<MediaRoute2Info> changedRoutes = new ArrayList<>();
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001274 if (prevInfo == null) {
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001275 mLastProviderInfos.add(currentInfo);
1276 addedRoutes.addAll(currentInfo.getRoutes());
1277 } else if (currentInfo == null) {
Hyundo Moon63a05402019-12-19 20:13:56 +09001278 mLastProviderInfos.remove(prevInfo);
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001279 removedRoutes.addAll(prevInfo.getRoutes());
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001280 } else {
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001281 mLastProviderInfos.set(providerInfoIndex, currentInfo);
1282 final Collection<MediaRoute2Info> prevRoutes = prevInfo.getRoutes();
1283 final Collection<MediaRoute2Info> currentRoutes = currentInfo.getRoutes();
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001284
1285 for (MediaRoute2Info route : currentRoutes) {
1286 if (!route.isValid()) {
Hyundo Moon369be952020-06-11 17:37:01 +09001287 Slog.w(TAG, "onProviderStateChangedOnHandler: Ignoring invalid route : "
1288 + route);
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001289 continue;
1290 }
Kyunglyul Hyun616096e2020-01-09 16:15:03 +09001291 MediaRoute2Info prevRoute = prevInfo.getRoute(route.getOriginalId());
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001292 if (prevRoute == null) {
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001293 addedRoutes.add(route);
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001294 } else if (!Objects.equals(prevRoute, route)) {
1295 changedRoutes.add(route);
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001296 }
1297 }
1298
1299 for (MediaRoute2Info prevRoute : prevInfo.getRoutes()) {
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001300 if (currentInfo.getRoute(prevRoute.getOriginalId()) == null) {
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001301 removedRoutes.add(prevRoute);
1302 }
1303 }
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001304 }
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001305
Sungsoo Limc27785a2020-03-27 16:57:47 +09001306 List<IMediaRouter2> routersWithModifyAudioRoutingPermission = getRouters(true);
1307 List<IMediaRouter2> routersWithoutModifyAudioRoutingPermission = getRouters(false);
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001308 List<IMediaRouter2Manager> managers = getManagers();
Sungsoo Limc27785a2020-03-27 16:57:47 +09001309 List<MediaRoute2Info> defaultRoute = new ArrayList<>();
1310 defaultRoute.add(mSystemProvider.getDefaultRoute());
1311
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001312 if (addedRoutes.size() > 0) {
Sungsoo Limc27785a2020-03-27 16:57:47 +09001313 notifyRoutesAddedToRouters(routersWithModifyAudioRoutingPermission, addedRoutes);
1314 if (!provider.mIsSystemRouteProvider) {
1315 notifyRoutesAddedToRouters(routersWithoutModifyAudioRoutingPermission,
1316 addedRoutes);
1317 } else if (prevInfo == null) {
1318 notifyRoutesAddedToRouters(routersWithoutModifyAudioRoutingPermission,
1319 defaultRoute);
1320 } // 'else' is handled as changed routes
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001321 notifyRoutesAddedToManagers(managers, addedRoutes);
1322 }
1323 if (removedRoutes.size() > 0) {
Sungsoo Limc27785a2020-03-27 16:57:47 +09001324 notifyRoutesRemovedToRouters(routersWithModifyAudioRoutingPermission,
1325 removedRoutes);
1326 if (!provider.mIsSystemRouteProvider) {
1327 notifyRoutesRemovedToRouters(routersWithoutModifyAudioRoutingPermission,
1328 removedRoutes);
1329 }
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001330 notifyRoutesRemovedToManagers(managers, removedRoutes);
1331 }
1332 if (changedRoutes.size() > 0) {
Sungsoo Limc27785a2020-03-27 16:57:47 +09001333 notifyRoutesChangedToRouters(routersWithModifyAudioRoutingPermission,
1334 changedRoutes);
1335 if (!provider.mIsSystemRouteProvider) {
1336 notifyRoutesChangedToRouters(routersWithoutModifyAudioRoutingPermission,
1337 changedRoutes);
1338 } else if (prevInfo != null) {
1339 notifyRoutesChangedToRouters(routersWithoutModifyAudioRoutingPermission,
1340 defaultRoute);
1341 } // 'else' is handled as added routes
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001342 notifyRoutesChangedToManagers(managers, changedRoutes);
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001343 }
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001344 }
1345
Sungsoo Limddf140d2020-03-25 08:53:55 +09001346 private int getLastProviderInfoIndex(@NonNull String providerId) {
Hyundo Moon63a05402019-12-19 20:13:56 +09001347 for (int i = 0; i < mLastProviderInfos.size(); i++) {
1348 MediaRoute2ProviderInfo providerInfo = mLastProviderInfos.get(i);
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001349 if (TextUtils.equals(providerInfo.getUniqueId(), providerId)) {
1350 return i;
1351 }
1352 }
1353 return -1;
1354 }
1355
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +09001356 private void requestRouterCreateSessionOnHandler(long uniqueRequestId,
Kyunglyul Hyunf0eb51b2020-04-14 19:56:16 +09001357 @NonNull RouterRecord routerRecord, @NonNull ManagerRecord managerRecord,
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +09001358 @NonNull RoutingSessionInfo oldSession, @NonNull MediaRoute2Info route) {
Kyunglyul Hyunf0eb51b2020-04-14 19:56:16 +09001359 try {
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +09001360 if (route.isSystemRoute() && !routerRecord.mHasModifyAudioRoutingPermission) {
1361 routerRecord.mRouter.requestCreateSessionByManager(uniqueRequestId,
1362 oldSession, mSystemProvider.getDefaultRoute());
1363 } else {
1364 routerRecord.mRouter.requestCreateSessionByManager(uniqueRequestId,
1365 oldSession, route);
1366 }
Kyunglyul Hyunf0eb51b2020-04-14 19:56:16 +09001367 } catch (RemoteException ex) {
Hyundo Moon369be952020-06-11 17:37:01 +09001368 Slog.w(TAG, "getSessionHintsForCreatingSessionOnHandler: "
1369 + "Failed to request. Router probably died.", ex);
Kyunglyul Hyunf0eb51b2020-04-14 19:56:16 +09001370 notifyRequestFailedToManager(managerRecord.mManager,
1371 toOriginalRequestId(uniqueRequestId), REASON_UNKNOWN_ERROR);
1372 }
1373 }
1374
1375 private void requestCreateSessionWithRouter2OnHandler(long uniqueRequestId,
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +09001376 long managerRequestId, @NonNull RouterRecord routerRecord,
1377 @NonNull RoutingSessionInfo oldSession,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001378 @NonNull MediaRoute2Info route, @Nullable Bundle sessionHints) {
Hyundo Moon63a05402019-12-19 20:13:56 +09001379
1380 final MediaRoute2Provider provider = findProvider(route.getProviderId());
1381 if (provider == null) {
Hyundo Moon369be952020-06-11 17:37:01 +09001382 Slog.w(TAG, "requestCreateSessionWithRouter2OnHandler: Ignoring session "
1383 + "creation request since no provider found for given route=" + route);
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001384 notifySessionCreationFailedToRouter(routerRecord,
1385 toOriginalRequestId(uniqueRequestId));
Hyundo Moon63a05402019-12-19 20:13:56 +09001386 return;
1387 }
1388
Hyundo Moondc79a7a2020-01-16 15:18:33 +09001389 SessionCreationRequest request =
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +09001390 new SessionCreationRequest(routerRecord, uniqueRequestId,
1391 managerRequestId, oldSession, route);
Hyundo Moon63a05402019-12-19 20:13:56 +09001392 mSessionCreationRequests.add(request);
1393
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001394 provider.requestCreateSession(uniqueRequestId, routerRecord.mPackageName,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001395 route.getOriginalId(), sessionHints);
Hyundo Moon63a05402019-12-19 20:13:56 +09001396 }
1397
Kyunglyul Hyuna69280b2020-04-03 15:15:09 +09001398 // routerRecord can be null if the session is system's or RCN.
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001399 private void selectRouteOnHandler(long uniqueRequestId, @Nullable RouterRecord routerRecord,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001400 @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
Hyundo Moon56337492020-02-16 16:19:54 +09001401 if (!checkArgumentsForSessionControl(routerRecord, uniqueSessionId, route,
Hyundo Moon0a926572019-12-28 15:01:21 +09001402 "selecting")) {
1403 return;
1404 }
1405
1406 final String providerId = route.getProviderId();
1407 final MediaRoute2Provider provider = findProvider(providerId);
Hyundo Moon0a926572019-12-28 15:01:21 +09001408 if (provider == null) {
1409 return;
1410 }
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001411 provider.selectRoute(uniqueRequestId, getOriginalId(uniqueSessionId),
1412 route.getOriginalId());
Hyundo Moon0a926572019-12-28 15:01:21 +09001413 }
1414
Kyunglyul Hyuna69280b2020-04-03 15:15:09 +09001415 // routerRecord can be null if the session is system's or RCN.
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001416 private void deselectRouteOnHandler(long uniqueRequestId,
1417 @Nullable RouterRecord routerRecord,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001418 @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
Hyundo Moon56337492020-02-16 16:19:54 +09001419 if (!checkArgumentsForSessionControl(routerRecord, uniqueSessionId, route,
Hyundo Moon0a926572019-12-28 15:01:21 +09001420 "deselecting")) {
1421 return;
1422 }
1423
1424 final String providerId = route.getProviderId();
1425 final MediaRoute2Provider provider = findProvider(providerId);
Hyundo Moon0a926572019-12-28 15:01:21 +09001426 if (provider == null) {
1427 return;
1428 }
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001429
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001430 provider.deselectRoute(uniqueRequestId, getOriginalId(uniqueSessionId),
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001431 route.getOriginalId());
Hyundo Moon0a926572019-12-28 15:01:21 +09001432 }
1433
Kyunglyul Hyuna69280b2020-04-03 15:15:09 +09001434 // routerRecord can be null if the session is system's or RCN.
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001435 private void transferToRouteOnHandler(long uniqueRequestId,
1436 @Nullable RouterRecord routerRecord,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001437 @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
Hyundo Moon56337492020-02-16 16:19:54 +09001438 if (!checkArgumentsForSessionControl(routerRecord, uniqueSessionId, route,
Hyundo Moon0a926572019-12-28 15:01:21 +09001439 "transferring to")) {
1440 return;
1441 }
1442
1443 final String providerId = route.getProviderId();
1444 final MediaRoute2Provider provider = findProvider(providerId);
Hyundo Moon0a926572019-12-28 15:01:21 +09001445 if (provider == null) {
1446 return;
1447 }
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001448 provider.transferToRoute(uniqueRequestId, getOriginalId(uniqueSessionId),
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001449 route.getOriginalId());
Hyundo Moon0a926572019-12-28 15:01:21 +09001450 }
1451
Kyunglyul Hyuna69280b2020-04-03 15:15:09 +09001452 // routerRecord is null if and only if the session is created without the request, which
1453 // includes the system's session and RCN cases.
Hyundo Moon56337492020-02-16 16:19:54 +09001454 private boolean checkArgumentsForSessionControl(@Nullable RouterRecord routerRecord,
Hyundo Moone962ed42020-02-16 19:47:41 +09001455 @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route,
1456 @NonNull String description) {
Hyundo Moon0a926572019-12-28 15:01:21 +09001457 final String providerId = route.getProviderId();
1458 final MediaRoute2Provider provider = findProvider(providerId);
1459 if (provider == null) {
1460 Slog.w(TAG, "Ignoring " + description + " route since no provider found for "
1461 + "given route=" + route);
1462 return false;
1463 }
1464
Hyundo Moon56337492020-02-16 16:19:54 +09001465 // Bypass checking router if it's the system session (routerRecord should be null)
Kyunglyul Hyun581fc982020-01-21 16:30:28 +09001466 if (TextUtils.equals(getProviderId(uniqueSessionId), mSystemProvider.getUniqueId())) {
1467 return true;
1468 }
1469
Hyundo Moon56337492020-02-16 16:19:54 +09001470 RouterRecord matchingRecord = mSessionToRouterMap.get(uniqueSessionId);
1471 if (matchingRecord != routerRecord) {
1472 Slog.w(TAG, "Ignoring " + description + " route from non-matching router. "
1473 + "packageName=" + routerRecord.mPackageName + " route=" + route);
Hyundo Moon0a926572019-12-28 15:01:21 +09001474 return false;
1475 }
1476
Hyundo Moonb26c4b22020-01-08 19:44:43 +09001477 final String sessionId = getOriginalId(uniqueSessionId);
Hyundo Moonca9db782020-01-01 18:31:15 +09001478 if (sessionId == null) {
Hyundo Moonb26c4b22020-01-08 19:44:43 +09001479 Slog.w(TAG, "Failed to get original session id from unique session id. "
Hyundo Moonca9db782020-01-01 18:31:15 +09001480 + "uniqueSessionId=" + uniqueSessionId);
Hyundo Moon0a926572019-12-28 15:01:21 +09001481 return false;
1482 }
1483
1484 return true;
1485 }
1486
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001487 private void setRouteVolumeOnHandler(long uniqueRequestId, @NonNull MediaRoute2Info route,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001488 int volume) {
1489 final MediaRoute2Provider provider = findProvider(route.getProviderId());
1490 if (provider == null) {
Hyundo Moon369be952020-06-11 17:37:01 +09001491 Slog.w(TAG, "setRouteVolumeOnHandler: Couldn't find provider for route=" + route);
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001492 return;
1493 }
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001494 provider.setRouteVolume(uniqueRequestId, route.getOriginalId(), volume);
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001495 }
1496
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001497 private void setSessionVolumeOnHandler(long uniqueRequestId,
1498 @NonNull String uniqueSessionId, int volume) {
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001499 final MediaRoute2Provider provider = findProvider(getProviderId(uniqueSessionId));
1500 if (provider == null) {
Hyundo Moon369be952020-06-11 17:37:01 +09001501 Slog.w(TAG, "setSessionVolumeOnHandler: Couldn't find provider for session id="
1502 + uniqueSessionId);
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001503 return;
1504 }
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001505 provider.setSessionVolume(uniqueRequestId, getOriginalId(uniqueSessionId), volume);
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001506 }
1507
1508 private void releaseSessionOnHandler(long uniqueRequestId,
Hyundo Moon1f066682020-04-13 04:04:15 +09001509 @Nullable RouterRecord routerRecord, @NonNull String uniqueSessionId) {
Hyundo Moon56337492020-02-16 16:19:54 +09001510 final RouterRecord matchingRecord = mSessionToRouterMap.get(uniqueSessionId);
1511 if (matchingRecord != routerRecord) {
Hyundo Moon1f066682020-04-13 04:04:15 +09001512 Slog.w(TAG, "Ignoring releasing session from non-matching router. packageName="
1513 + (routerRecord == null ? null : routerRecord.mPackageName)
Hyundo Moonca9db782020-01-01 18:31:15 +09001514 + " uniqueSessionId=" + uniqueSessionId);
1515 return;
1516 }
1517
Hyundo Moonb26c4b22020-01-08 19:44:43 +09001518 final String providerId = getProviderId(uniqueSessionId);
Hyundo Moonca9db782020-01-01 18:31:15 +09001519 if (providerId == null) {
1520 Slog.w(TAG, "Ignoring releasing session with invalid unique session ID. "
1521 + "uniqueSessionId=" + uniqueSessionId);
1522 return;
1523 }
1524
Hyundo Moonb26c4b22020-01-08 19:44:43 +09001525 final String sessionId = getOriginalId(uniqueSessionId);
Hyundo Moonca9db782020-01-01 18:31:15 +09001526 if (sessionId == null) {
1527 Slog.w(TAG, "Ignoring releasing session with invalid unique session ID. "
1528 + "uniqueSessionId=" + uniqueSessionId + " providerId=" + providerId);
1529 return;
1530 }
1531
1532 final MediaRoute2Provider provider = findProvider(providerId);
1533 if (provider == null) {
1534 Slog.w(TAG, "Ignoring releasing session since no provider found for given "
1535 + "providerId=" + providerId);
1536 return;
1537 }
1538
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001539 provider.releaseSession(uniqueRequestId, sessionId);
Hyundo Moonca9db782020-01-01 18:31:15 +09001540 }
1541
1542 private void onSessionCreatedOnHandler(@NonNull MediaRoute2Provider provider,
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001543 long uniqueRequestId, @NonNull RoutingSessionInfo sessionInfo) {
Hyundo Moon63a05402019-12-19 20:13:56 +09001544 SessionCreationRequest matchingRequest = null;
Kyunglyul Hyuncb8894d2019-12-27 14:24:46 +09001545
Hyundo Moon63a05402019-12-19 20:13:56 +09001546 for (SessionCreationRequest request : mSessionCreationRequests) {
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001547 if (request.mUniqueRequestId == uniqueRequestId
Hyundo Moon63a05402019-12-19 20:13:56 +09001548 && TextUtils.equals(
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +09001549 request.mRoute.getProviderId(), provider.getUniqueId())) {
Hyundo Moon63a05402019-12-19 20:13:56 +09001550 matchingRequest = request;
1551 break;
1552 }
1553 }
1554
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +09001555 long managerRequestId = (matchingRequest == null)
1556 ? MediaRoute2ProviderService.REQUEST_ID_NONE
1557 : matchingRequest.mManagerRequestId;
1558 // Managers should know created session even if it's not requested.
1559 notifySessionCreatedToManagers(managerRequestId, sessionInfo);
1560
Hyundo Moon63a05402019-12-19 20:13:56 +09001561 if (matchingRequest == null) {
1562 Slog.w(TAG, "Ignoring session creation result for unknown request. "
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001563 + "uniqueRequestId=" + uniqueRequestId + ", sessionInfo=" + sessionInfo);
Hyundo Moon63a05402019-12-19 20:13:56 +09001564 return;
1565 }
1566
Kyunglyul Hyuncb8894d2019-12-27 14:24:46 +09001567 mSessionCreationRequests.remove(matchingRequest);
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +09001568 // Not to show old session
1569 MediaRoute2Provider oldProvider =
1570 findProvider(matchingRequest.mOldSession.getProviderId());
1571 if (oldProvider != null) {
1572 oldProvider.prepareReleaseSession(matchingRequest.mOldSession.getId());
1573 } else {
1574 Slog.w(TAG, "onSessionCreatedOnHandler: Can't find provider for an old session. "
1575 + "session=" + matchingRequest.mOldSession);
Hyundo Moon63a05402019-12-19 20:13:56 +09001576 }
1577
1578 String originalRouteId = matchingRequest.mRoute.getId();
Hyundo Moon56337492020-02-16 16:19:54 +09001579 RouterRecord routerRecord = matchingRequest.mRouterRecord;
Hyundo Moon0a926572019-12-28 15:01:21 +09001580
Hyundo Moondc79a7a2020-01-16 15:18:33 +09001581 if (!sessionInfo.getSelectedRoutes().contains(originalRouteId)) {
Hyundo Moon63a05402019-12-19 20:13:56 +09001582 Slog.w(TAG, "Created session doesn't match the original request."
1583 + " originalRouteId=" + originalRouteId
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001584 + ", uniqueRequestId=" + uniqueRequestId + ", sessionInfo=" + sessionInfo);
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001585 notifySessionCreationFailedToRouter(matchingRequest.mRouterRecord,
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001586 toOriginalRequestId(uniqueRequestId));
Hyundo Moon63a05402019-12-19 20:13:56 +09001587 return;
1588 }
1589
1590 // Succeeded
Kyunglyul Hyun22d4e052020-04-21 10:10:48 +09001591 if (sessionInfo.isSystemSession()
1592 && !matchingRequest.mRouterRecord.mHasModifyAudioRoutingPermission) {
1593 notifySessionCreatedToRouter(matchingRequest.mRouterRecord,
1594 toOriginalRequestId(uniqueRequestId),
1595 mSystemProvider.getDefaultSessionInfo());
1596 } else {
1597 notifySessionCreatedToRouter(matchingRequest.mRouterRecord,
1598 toOriginalRequestId(uniqueRequestId), sessionInfo);
1599 }
Hyundo Moon56337492020-02-16 16:19:54 +09001600 mSessionToRouterMap.put(sessionInfo.getId(), routerRecord);
Hyundo Moon63a05402019-12-19 20:13:56 +09001601 }
1602
Hyundo Moonca9db782020-01-01 18:31:15 +09001603 private void onSessionInfoChangedOnHandler(@NonNull MediaRoute2Provider provider,
Hyundo Moonf829e6f2020-01-11 19:31:35 +09001604 @NonNull RoutingSessionInfo sessionInfo) {
Kyunglyul Hyunc6583832020-01-17 11:11:46 +00001605 List<IMediaRouter2Manager> managers = getManagers();
Kyunglyul Hyunfe7b5b12020-06-04 20:17:59 +09001606 notifySessionUpdatedToManagers(managers, sessionInfo);
Hyundo Moon0a926572019-12-28 15:01:21 +09001607
Hyundo Moon56337492020-02-16 16:19:54 +09001608 // For system provider, notify all routers.
Hyundo Moon67c41fd2020-01-17 14:22:42 +09001609 if (provider == mSystemProvider) {
1610 MediaRouter2ServiceImpl service = mServiceRef.get();
1611 if (service == null) {
1612 return;
1613 }
Sungsoo Limc27785a2020-03-27 16:57:47 +09001614 notifySessionInfoChangedToRouters(getRouters(true), sessionInfo);
1615 notifySessionInfoChangedToRouters(getRouters(false),
1616 mSystemProvider.getDefaultSessionInfo());
Hyundo Moon67c41fd2020-01-17 14:22:42 +09001617 return;
1618 }
1619
Hyundo Moon56337492020-02-16 16:19:54 +09001620 RouterRecord routerRecord = mSessionToRouterMap.get(sessionInfo.getId());
1621 if (routerRecord == null) {
Hyundo Moon369be952020-06-11 17:37:01 +09001622 Slog.w(TAG, "onSessionInfoChangedOnHandler: No matching router found for session="
1623 + sessionInfo);
Hyundo Moon0a926572019-12-28 15:01:21 +09001624 return;
1625 }
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001626 notifySessionInfoChangedToRouter(routerRecord, sessionInfo);
Hyundo Moon0a926572019-12-28 15:01:21 +09001627 }
1628
Hyundo Moonca9db782020-01-01 18:31:15 +09001629 private void onSessionReleasedOnHandler(@NonNull MediaRoute2Provider provider,
Hyundo Moonf829e6f2020-01-11 19:31:35 +09001630 @NonNull RoutingSessionInfo sessionInfo) {
Kyunglyul Hyunc6583832020-01-17 11:11:46 +00001631 List<IMediaRouter2Manager> managers = getManagers();
Kyunglyul Hyunfe7b5b12020-06-04 20:17:59 +09001632 notifySessionReleasedToManagers(managers, sessionInfo);
Hyundo Moonca9db782020-01-01 18:31:15 +09001633
Hyundo Moon56337492020-02-16 16:19:54 +09001634 RouterRecord routerRecord = mSessionToRouterMap.get(sessionInfo.getId());
1635 if (routerRecord == null) {
Hyundo Moon369be952020-06-11 17:37:01 +09001636 Slog.w(TAG, "onSessionReleasedOnHandler: No matching router found for session="
1637 + sessionInfo);
Hyundo Moonca9db782020-01-01 18:31:15 +09001638 return;
1639 }
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001640 notifySessionReleasedToRouter(routerRecord, sessionInfo);
Hyundo Moonca9db782020-01-01 18:31:15 +09001641 }
1642
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001643 private void onRequestFailedOnHandler(@NonNull MediaRoute2Provider provider,
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001644 long uniqueRequestId, int reason) {
1645 if (handleSessionCreationRequestFailed(provider, uniqueRequestId, reason)) {
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001646 return;
1647 }
1648
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001649 final int requesterId = toRequesterId(uniqueRequestId);
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +09001650 ManagerRecord manager = findManagerWithId(requesterId);
1651 if (manager != null) {
1652 notifyRequestFailedToManager(
1653 manager.mManager, toOriginalRequestId(uniqueRequestId), reason);
1654 return;
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001655 }
1656
Hyundo Moon7c2059c2020-02-27 19:01:52 +09001657 // Currently, only the manager can get notified of failures.
1658 // TODO: Notify router too when the related callback is introduced.
1659 }
1660
Hyundo Moon7c2059c2020-02-27 19:01:52 +09001661 private boolean handleSessionCreationRequestFailed(@NonNull MediaRoute2Provider provider,
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001662 long uniqueRequestId, int reason) {
Hyundo Moon7c2059c2020-02-27 19:01:52 +09001663 // Check whether the failure is about creating a session
1664 SessionCreationRequest matchingRequest = null;
1665 for (SessionCreationRequest request : mSessionCreationRequests) {
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001666 if (request.mUniqueRequestId == uniqueRequestId && TextUtils.equals(
Hyundo Moon7c2059c2020-02-27 19:01:52 +09001667 request.mRoute.getProviderId(), provider.getUniqueId())) {
1668 matchingRequest = request;
1669 break;
1670 }
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001671 }
1672
Hyundo Moon7c2059c2020-02-27 19:01:52 +09001673 if (matchingRequest == null) {
1674 // The failure is not about creating a session.
1675 return false;
1676 }
1677
1678 mSessionCreationRequests.remove(matchingRequest);
1679
1680 // Notify the requester about the failure.
1681 // The call should be made by either MediaRouter2 or MediaRouter2Manager.
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +09001682 if (matchingRequest.mManagerRequestId == MediaRouter2Manager.REQUEST_ID_NONE) {
Hyundo Moon7c2059c2020-02-27 19:01:52 +09001683 notifySessionCreationFailedToRouter(
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001684 matchingRequest.mRouterRecord, toOriginalRequestId(uniqueRequestId));
Hyundo Moon7c2059c2020-02-27 19:01:52 +09001685 } else {
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +09001686 final int requesterId = toRequesterId(matchingRequest.mManagerRequestId);
1687 ManagerRecord manager = findManagerWithId(requesterId);
1688 if (manager != null) {
1689 notifyRequestFailedToManager(manager.mManager,
1690 toOriginalRequestId(matchingRequest.mManagerRequestId), reason);
1691 }
Hyundo Moon7c2059c2020-02-27 19:01:52 +09001692 }
1693 return true;
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001694 }
1695
1696 private void notifySessionCreatedToRouter(@NonNull RouterRecord routerRecord,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001697 int requestId, @NonNull RoutingSessionInfo sessionInfo) {
Hyundo Moon63a05402019-12-19 20:13:56 +09001698 try {
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001699 routerRecord.mRouter.notifySessionCreated(requestId, sessionInfo);
Hyundo Moon63a05402019-12-19 20:13:56 +09001700 } catch (RemoteException ex) {
Hyundo Moon56337492020-02-16 16:19:54 +09001701 Slog.w(TAG, "Failed to notify router of the session creation."
1702 + " Router probably died.", ex);
Hyundo Moon63a05402019-12-19 20:13:56 +09001703 }
1704 }
1705
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001706 private void notifySessionCreationFailedToRouter(@NonNull RouterRecord routerRecord,
Hyundo Moone962ed42020-02-16 19:47:41 +09001707 int requestId) {
Hyundo Moon63a05402019-12-19 20:13:56 +09001708 try {
Kyunglyul Hyunf064dcae2020-03-06 22:59:14 +09001709 routerRecord.mRouter.notifySessionCreated(requestId,
1710 /* sessionInfo= */ null);
Hyundo Moon63a05402019-12-19 20:13:56 +09001711 } catch (RemoteException ex) {
Hyundo Moon56337492020-02-16 16:19:54 +09001712 Slog.w(TAG, "Failed to notify router of the session creation failure."
1713 + " Router probably died.", ex);
Hyundo Moon63a05402019-12-19 20:13:56 +09001714 }
1715 }
1716
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001717 private void notifySessionInfoChangedToRouter(@NonNull RouterRecord routerRecord,
Hyundo Moone962ed42020-02-16 19:47:41 +09001718 @NonNull RoutingSessionInfo sessionInfo) {
Hyundo Moon0a926572019-12-28 15:01:21 +09001719 try {
Hyundo Moon56337492020-02-16 16:19:54 +09001720 routerRecord.mRouter.notifySessionInfoChanged(sessionInfo);
Hyundo Moon0a926572019-12-28 15:01:21 +09001721 } catch (RemoteException ex) {
Hyundo Moon56337492020-02-16 16:19:54 +09001722 Slog.w(TAG, "Failed to notify router of the session info change."
1723 + " Router probably died.", ex);
Hyundo Moon0a926572019-12-28 15:01:21 +09001724 }
1725 }
1726
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001727 private void notifySessionReleasedToRouter(@NonNull RouterRecord routerRecord,
Hyundo Moone962ed42020-02-16 19:47:41 +09001728 @NonNull RoutingSessionInfo sessionInfo) {
Hyundo Moonca9db782020-01-01 18:31:15 +09001729 try {
Hyundo Moon56337492020-02-16 16:19:54 +09001730 routerRecord.mRouter.notifySessionReleased(sessionInfo);
Hyundo Moonca9db782020-01-01 18:31:15 +09001731 } catch (RemoteException ex) {
Hyundo Moon56337492020-02-16 16:19:54 +09001732 Slog.w(TAG, "Failed to notify router of the session release."
1733 + " Router probably died.", ex);
Hyundo Moonca9db782020-01-01 18:31:15 +09001734 }
1735 }
1736
Sungsoo Limc27785a2020-03-27 16:57:47 +09001737 private List<IMediaRouter2> getAllRouters() {
Hyundo Moon56337492020-02-16 16:19:54 +09001738 final List<IMediaRouter2> routers = new ArrayList<>();
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001739 MediaRouter2ServiceImpl service = mServiceRef.get();
1740 if (service == null) {
Hyundo Moon56337492020-02-16 16:19:54 +09001741 return routers;
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001742 }
1743 synchronized (service.mLock) {
Hyundo Moon56337492020-02-16 16:19:54 +09001744 for (RouterRecord routerRecord : mUserRecord.mRouterRecords) {
1745 routers.add(routerRecord.mRouter);
Kyunglyul Hyun23b3aaa2019-08-06 11:17:16 +09001746 }
1747 }
Hyundo Moon56337492020-02-16 16:19:54 +09001748 return routers;
Kyunglyul Hyun23b3aaa2019-08-06 11:17:16 +09001749 }
1750
Sungsoo Limc27785a2020-03-27 16:57:47 +09001751 private List<IMediaRouter2> getRouters(boolean hasModifyAudioRoutingPermission) {
1752 final List<IMediaRouter2> routers = new ArrayList<>();
1753 MediaRouter2ServiceImpl service = mServiceRef.get();
1754 if (service == null) {
1755 return routers;
1756 }
1757 synchronized (service.mLock) {
1758 for (RouterRecord routerRecord : mUserRecord.mRouterRecords) {
1759 if (hasModifyAudioRoutingPermission
1760 == routerRecord.mHasModifyAudioRoutingPermission) {
1761 routers.add(routerRecord.mRouter);
1762 }
1763 }
1764 }
1765 return routers;
1766 }
1767
Kyunglyul Hyun4ed68752019-11-04 16:05:34 +09001768 private List<IMediaRouter2Manager> getManagers() {
1769 final List<IMediaRouter2Manager> managers = new ArrayList<>();
1770 MediaRouter2ServiceImpl service = mServiceRef.get();
1771 if (service == null) {
1772 return managers;
1773 }
1774 synchronized (service.mLock) {
1775 for (ManagerRecord managerRecord : mUserRecord.mManagerRecords) {
1776 managers.add(managerRecord.mManager);
1777 }
1778 }
1779 return managers;
1780 }
1781
Hyundo Moon7c2059c2020-02-27 19:01:52 +09001782 private List<ManagerRecord> getManagerRecords() {
1783 MediaRouter2ServiceImpl service = mServiceRef.get();
1784 if (service == null) {
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001785 return Collections.emptyList();
Hyundo Moon7c2059c2020-02-27 19:01:52 +09001786 }
1787 synchronized (service.mLock) {
1788 return new ArrayList<>(mUserRecord.mManagerRecords);
1789 }
1790 }
1791
Hyundo Moonbc633272020-06-04 18:12:29 +09001792 private void notifyRouterRegistered(@NonNull RouterRecord routerRecord) {
1793 List<MediaRoute2Info> currentRoutes = new ArrayList<>();
Hyundo Moonfa248a72020-05-12 20:05:27 +09001794
1795 MediaRoute2ProviderInfo systemProviderInfo = null;
Hyundo Moon63a05402019-12-19 20:13:56 +09001796 for (MediaRoute2ProviderInfo providerInfo : mLastProviderInfos) {
Hyundo Moonfa248a72020-05-12 20:05:27 +09001797 // TODO: Create MediaRoute2ProviderInfo#isSystemProvider()
1798 if (TextUtils.equals(providerInfo.getUniqueId(), mSystemProvider.getUniqueId())) {
1799 // Adding routes from system provider will be handled below, so skip it here.
1800 systemProviderInfo = providerInfo;
1801 continue;
1802 }
Hyundo Moonbc633272020-06-04 18:12:29 +09001803 currentRoutes.addAll(providerInfo.getRoutes());
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001804 }
Hyundo Moonfa248a72020-05-12 20:05:27 +09001805
Hyundo Moonbc633272020-06-04 18:12:29 +09001806 RoutingSessionInfo currentSystemSessionInfo;
Hyundo Moonfa248a72020-05-12 20:05:27 +09001807 if (routerRecord.mHasModifyAudioRoutingPermission) {
1808 if (systemProviderInfo != null) {
Hyundo Moonbc633272020-06-04 18:12:29 +09001809 currentRoutes.addAll(systemProviderInfo.getRoutes());
Hyundo Moonfa248a72020-05-12 20:05:27 +09001810 } else {
1811 // This shouldn't happen.
Hyundo Moon369be952020-06-11 17:37:01 +09001812 Slog.wtf(TAG, "System route provider not found.");
Hyundo Moonfa248a72020-05-12 20:05:27 +09001813 }
Hyundo Moonbc633272020-06-04 18:12:29 +09001814 currentSystemSessionInfo = mSystemProvider.getSessionInfos().get(0);
Hyundo Moonfa248a72020-05-12 20:05:27 +09001815 } else {
Hyundo Moonbc633272020-06-04 18:12:29 +09001816 currentRoutes.add(mSystemProvider.getDefaultRoute());
1817 currentSystemSessionInfo = mSystemProvider.getDefaultSessionInfo();
Hyundo Moonfa248a72020-05-12 20:05:27 +09001818 }
1819
Hyundo Moonbc633272020-06-04 18:12:29 +09001820 if (currentRoutes.size() == 0) {
Kyunglyul Hyun23b3aaa2019-08-06 11:17:16 +09001821 return;
1822 }
Hyundo Moonbc633272020-06-04 18:12:29 +09001823
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001824 try {
Hyundo Moonbc633272020-06-04 18:12:29 +09001825 routerRecord.mRouter.notifyRouterRegistered(
1826 currentRoutes, currentSystemSessionInfo);
Kyunglyul Hyun23b3aaa2019-08-06 11:17:16 +09001827 } catch (RemoteException ex) {
Hyundo Moonbc633272020-06-04 18:12:29 +09001828 Slog.w(TAG, "Failed to notify router registered. Router probably died.", ex);
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001829 }
1830 }
1831
Hyundo Moone962ed42020-02-16 19:47:41 +09001832 private void notifyRoutesAddedToRouters(@NonNull List<IMediaRouter2> routers,
1833 @NonNull List<MediaRoute2Info> routes) {
Hyundo Moon56337492020-02-16 16:19:54 +09001834 for (IMediaRouter2 router : routers) {
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001835 try {
Hyundo Moon56337492020-02-16 16:19:54 +09001836 router.notifyRoutesAdded(routes);
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001837 } catch (RemoteException ex) {
Hyundo Moon56337492020-02-16 16:19:54 +09001838 Slog.w(TAG, "Failed to notify routes added. Router probably died.", ex);
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001839 }
1840 }
1841 }
1842
Hyundo Moone962ed42020-02-16 19:47:41 +09001843 private void notifyRoutesRemovedToRouters(@NonNull List<IMediaRouter2> routers,
1844 @NonNull List<MediaRoute2Info> routes) {
Hyundo Moon56337492020-02-16 16:19:54 +09001845 for (IMediaRouter2 router : routers) {
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001846 try {
Hyundo Moon56337492020-02-16 16:19:54 +09001847 router.notifyRoutesRemoved(routes);
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001848 } catch (RemoteException ex) {
Hyundo Moon56337492020-02-16 16:19:54 +09001849 Slog.w(TAG, "Failed to notify routes removed. Router probably died.", ex);
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001850 }
1851 }
1852 }
1853
Hyundo Moone962ed42020-02-16 19:47:41 +09001854 private void notifyRoutesChangedToRouters(@NonNull List<IMediaRouter2> routers,
1855 @NonNull List<MediaRoute2Info> routes) {
Hyundo Moon56337492020-02-16 16:19:54 +09001856 for (IMediaRouter2 router : routers) {
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001857 try {
Hyundo Moon56337492020-02-16 16:19:54 +09001858 router.notifyRoutesChanged(routes);
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001859 } catch (RemoteException ex) {
Hyundo Moon56337492020-02-16 16:19:54 +09001860 Slog.w(TAG, "Failed to notify routes changed. Router probably died.", ex);
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001861 }
Kyunglyul Hyun23b3aaa2019-08-06 11:17:16 +09001862 }
1863 }
1864
Hyundo Moone962ed42020-02-16 19:47:41 +09001865 private void notifySessionInfoChangedToRouters(@NonNull List<IMediaRouter2> routers,
1866 @NonNull RoutingSessionInfo sessionInfo) {
Hyundo Moon56337492020-02-16 16:19:54 +09001867 for (IMediaRouter2 router : routers) {
Hyundo Moon67c41fd2020-01-17 14:22:42 +09001868 try {
Hyundo Moon56337492020-02-16 16:19:54 +09001869 router.notifySessionInfoChanged(sessionInfo);
Hyundo Moon67c41fd2020-01-17 14:22:42 +09001870 } catch (RemoteException ex) {
Hyundo Moon56337492020-02-16 16:19:54 +09001871 Slog.w(TAG, "Failed to notify session info changed. Router probably died.", ex);
Hyundo Moon67c41fd2020-01-17 14:22:42 +09001872 }
1873 }
1874 }
1875
Hyundo Moone962ed42020-02-16 19:47:41 +09001876 private void notifyRoutesToManager(@NonNull IMediaRouter2Manager manager) {
Kyunglyul Hyun4ed68752019-11-04 16:05:34 +09001877 List<MediaRoute2Info> routes = new ArrayList<>();
Hyundo Moon63a05402019-12-19 20:13:56 +09001878 for (MediaRoute2ProviderInfo providerInfo : mLastProviderInfos) {
Kyunglyul Hyun4ed68752019-11-04 16:05:34 +09001879 routes.addAll(providerInfo.getRoutes());
1880 }
1881 if (routes.size() == 0) {
1882 return;
1883 }
Kyunglyul Hyun23b3aaa2019-08-06 11:17:16 +09001884 try {
Kyunglyul Hyun4ed68752019-11-04 16:05:34 +09001885 manager.notifyRoutesAdded(routes);
Kyunglyul Hyun23b3aaa2019-08-06 11:17:16 +09001886 } catch (RemoteException ex) {
Kyunglyul Hyun4ed68752019-11-04 16:05:34 +09001887 Slog.w(TAG, "Failed to notify all routes. Manager probably died.", ex);
1888 }
1889 }
1890
Hyundo Moone962ed42020-02-16 19:47:41 +09001891 private void notifyRoutesAddedToManagers(@NonNull List<IMediaRouter2Manager> managers,
1892 @NonNull List<MediaRoute2Info> routes) {
Kyunglyul Hyun4ed68752019-11-04 16:05:34 +09001893 for (IMediaRouter2Manager manager : managers) {
1894 try {
1895 manager.notifyRoutesAdded(routes);
1896 } catch (RemoteException ex) {
1897 Slog.w(TAG, "Failed to notify routes added. Manager probably died.", ex);
1898 }
1899 }
1900 }
1901
Hyundo Moone962ed42020-02-16 19:47:41 +09001902 private void notifyRoutesRemovedToManagers(@NonNull List<IMediaRouter2Manager> managers,
1903 @NonNull List<MediaRoute2Info> routes) {
Kyunglyul Hyun4ed68752019-11-04 16:05:34 +09001904 for (IMediaRouter2Manager manager : managers) {
1905 try {
1906 manager.notifyRoutesRemoved(routes);
1907 } catch (RemoteException ex) {
1908 Slog.w(TAG, "Failed to notify routes removed. Manager probably died.", ex);
1909 }
1910 }
1911 }
1912
Hyundo Moone962ed42020-02-16 19:47:41 +09001913 private void notifyRoutesChangedToManagers(@NonNull List<IMediaRouter2Manager> managers,
1914 @NonNull List<MediaRoute2Info> routes) {
Kyunglyul Hyun4ed68752019-11-04 16:05:34 +09001915 for (IMediaRouter2Manager manager : managers) {
1916 try {
1917 manager.notifyRoutesChanged(routes);
1918 } catch (RemoteException ex) {
1919 Slog.w(TAG, "Failed to notify routes changed. Manager probably died.", ex);
1920 }
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001921 }
1922 }
1923
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +09001924 private void notifySessionCreatedToManagers(long managerRequestId,
1925 @NonNull RoutingSessionInfo session) {
1926 int requesterId = toRequesterId(managerRequestId);
1927 int originalRequestId = toOriginalRequestId(managerRequestId);
1928
1929 for (ManagerRecord manager : getManagerRecords()) {
Kyunglyul Hyunc6583832020-01-17 11:11:46 +00001930 try {
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +09001931 manager.mManager.notifySessionCreated(
1932 ((manager.mManagerId == requesterId) ? originalRequestId :
1933 MediaRouter2Manager.REQUEST_ID_NONE), session);
Kyunglyul Hyunc6583832020-01-17 11:11:46 +00001934 } catch (RemoteException ex) {
1935 Slog.w(TAG, "notifySessionCreatedToManagers: "
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +09001936 + "Failed to notify. Manager probably died.", ex);
Kyunglyul Hyunc6583832020-01-17 11:11:46 +00001937 }
1938 }
1939 }
1940
Kyunglyul Hyunfe7b5b12020-06-04 20:17:59 +09001941 private void notifySessionUpdatedToManagers(
Kyunglyul Hyunf064dcae2020-03-06 22:59:14 +09001942 @NonNull List<IMediaRouter2Manager> managers,
1943 @NonNull RoutingSessionInfo sessionInfo) {
Kyunglyul Hyunc6583832020-01-17 11:11:46 +00001944 for (IMediaRouter2Manager manager : managers) {
1945 try {
Kyunglyul Hyunf064dcae2020-03-06 22:59:14 +09001946 manager.notifySessionUpdated(sessionInfo);
Kyunglyul Hyunc6583832020-01-17 11:11:46 +00001947 } catch (RemoteException ex) {
Kyunglyul Hyunfe7b5b12020-06-04 20:17:59 +09001948 Slog.w(TAG, "notifySessionUpdatedToManagers: "
1949 + "Failed to notify. Manager probably died.", ex);
1950 }
1951 }
1952 }
1953
1954 private void notifySessionReleasedToManagers(
1955 @NonNull List<IMediaRouter2Manager> managers,
1956 @NonNull RoutingSessionInfo sessionInfo) {
1957 for (IMediaRouter2Manager manager : managers) {
1958 try {
1959 manager.notifySessionReleased(sessionInfo);
1960 } catch (RemoteException ex) {
1961 Slog.w(TAG, "notifySessionReleasedToManagers: "
1962 + "Failed to notify. Manager probably died.", ex);
Kyunglyul Hyunc6583832020-01-17 11:11:46 +00001963 }
1964 }
1965 }
1966
Hyundo Moon38d06df2020-05-20 14:24:06 +09001967 private void notifyPreferredFeaturesChangedToManager(@NonNull RouterRecord routerRecord,
1968 @NonNull IMediaRouter2Manager manager) {
1969 try {
1970 manager.notifyPreferredFeaturesChanged(routerRecord.mPackageName,
1971 routerRecord.mDiscoveryPreference.getPreferredFeatures());
1972 } catch (RemoteException ex) {
1973 Slog.w(TAG, "Failed to notify preferred features changed."
1974 + " Manager probably died.", ex);
1975 }
1976 }
1977
Hyundo Moonac9df102020-06-12 19:36:10 +09001978 private void notifyPreferredFeaturesChangedToManagers(@NonNull String routerPackageName,
1979 @Nullable List<String> preferredFeatures) {
Kyunglyul Hyundafac542019-04-29 18:07:21 +09001980 MediaRouter2ServiceImpl service = mServiceRef.get();
1981 if (service == null) {
1982 return;
1983 }
1984 List<IMediaRouter2Manager> managers = new ArrayList<>();
1985 synchronized (service.mLock) {
Hyundo Moon7d3ab332019-10-16 11:09:56 +09001986 for (ManagerRecord managerRecord : mUserRecord.mManagerRecords) {
1987 managers.add(managerRecord.mManager);
Kyunglyul Hyundafac542019-04-29 18:07:21 +09001988 }
1989 }
Kyunglyul Hyun13bc1052019-05-31 17:00:36 +09001990 for (IMediaRouter2Manager manager : managers) {
Kyunglyul Hyundafac542019-04-29 18:07:21 +09001991 try {
Hyundo Moonac9df102020-06-12 19:36:10 +09001992 manager.notifyPreferredFeaturesChanged(routerPackageName, preferredFeatures);
Kyunglyul Hyundafac542019-04-29 18:07:21 +09001993 } catch (RemoteException ex) {
Hyundo Moon56337492020-02-16 16:19:54 +09001994 Slog.w(TAG, "Failed to notify preferred features changed."
1995 + " Manager probably died.", ex);
Kyunglyul Hyundafac542019-04-29 18:07:21 +09001996 }
1997 }
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001998 }
Kyunglyul Hyun13bc1052019-05-31 17:00:36 +09001999
Hyundo Moon0fa60e82020-02-14 11:44:45 +09002000 private void notifyRequestFailedToManager(@NonNull IMediaRouter2Manager manager,
2001 int requestId, int reason) {
2002 try {
2003 manager.notifyRequestFailed(requestId, reason);
2004 } catch (RemoteException ex) {
2005 Slog.w(TAG, "Failed to notify manager of the request failure."
2006 + " Manager probably died.", ex);
2007 }
2008 }
2009
2010 private void updateDiscoveryPreferenceOnHandler() {
Kyunglyul Hyun1866d8a2020-01-31 11:56:34 +09002011 MediaRouter2ServiceImpl service = mServiceRef.get();
2012 if (service == null) {
2013 return;
2014 }
2015 List<RouteDiscoveryPreference> discoveryPreferences = new ArrayList<>();
2016 synchronized (service.mLock) {
Hyundo Moon56337492020-02-16 16:19:54 +09002017 for (RouterRecord routerRecord : mUserRecord.mRouterRecords) {
2018 discoveryPreferences.add(routerRecord.mDiscoveryPreference);
Kyunglyul Hyun1866d8a2020-01-31 11:56:34 +09002019 }
2020 mUserRecord.mCompositeDiscoveryPreference =
2021 new RouteDiscoveryPreference.Builder(discoveryPreferences)
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +09002022 .build();
Kyunglyul Hyun1866d8a2020-01-31 11:56:34 +09002023 }
Sungsoo Limddf140d2020-03-25 08:53:55 +09002024 for (MediaRoute2Provider provider : mRouteProviders) {
Kyunglyul Hyun1866d8a2020-01-31 11:56:34 +09002025 provider.updateDiscoveryPreference(mUserRecord.mCompositeDiscoveryPreference);
2026 }
2027 }
2028
Hyundo Moone962ed42020-02-16 19:47:41 +09002029 private MediaRoute2Provider findProvider(@Nullable String providerId) {
Sungsoo Limddf140d2020-03-25 08:53:55 +09002030 for (MediaRoute2Provider provider : mRouteProviders) {
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09002031 if (TextUtils.equals(provider.getUniqueId(), providerId)) {
Kyunglyul Hyun13bc1052019-05-31 17:00:36 +09002032 return provider;
2033 }
2034 }
2035 return null;
2036 }
Hyundo Moon63a05402019-12-19 20:13:56 +09002037
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +09002038 }
2039 static final class SessionCreationRequest {
2040 public final RouterRecord mRouterRecord;
2041 public final long mUniqueRequestId;
2042 public final long mManagerRequestId;
2043 public final RoutingSessionInfo mOldSession;
2044 public final MediaRoute2Info mRoute;
Hyundo Moon63a05402019-12-19 20:13:56 +09002045
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +09002046 SessionCreationRequest(@NonNull RouterRecord routerRecord, long uniqueRequestId,
2047 long managerRequestId, @NonNull RoutingSessionInfo oldSession,
2048 @NonNull MediaRoute2Info route) {
2049 mRouterRecord = routerRecord;
2050 mUniqueRequestId = uniqueRequestId;
2051 mManagerRequestId = managerRequestId;
2052 mOldSession = oldSession;
2053 mRoute = route;
Hyundo Moon63a05402019-12-19 20:13:56 +09002054 }
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09002055 }
2056}