1 /*
2  * Copyright (C) 2014 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 
17 package com.android.server.media;
18 
19 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
20 import static android.os.UserHandle.ALL;
21 import static android.os.UserHandle.CURRENT;
22 
23 import static com.android.server.media.MediaKeyDispatcher.KEY_EVENT_LONG_PRESS;
24 import static com.android.server.media.MediaKeyDispatcher.isDoubleTapOverridden;
25 import static com.android.server.media.MediaKeyDispatcher.isLongPressOverridden;
26 import static com.android.server.media.MediaKeyDispatcher.isSingleTapOverridden;
27 import static com.android.server.media.MediaKeyDispatcher.isTripleTapOverridden;
28 
29 import android.annotation.NonNull;
30 import android.annotation.Nullable;
31 import android.app.ActivityManager;
32 import android.app.KeyguardManager;
33 import android.app.NotificationManager;
34 import android.app.PendingIntent;
35 import android.content.ActivityNotFoundException;
36 import android.content.BroadcastReceiver;
37 import android.content.ComponentName;
38 import android.content.ContentResolver;
39 import android.content.Context;
40 import android.content.Intent;
41 import android.content.IntentFilter;
42 import android.content.pm.PackageManager;
43 import android.content.pm.PackageManagerInternal;
44 import android.media.AudioManager;
45 import android.media.AudioPlaybackConfiguration;
46 import android.media.AudioSystem;
47 import android.media.IRemoteSessionCallback;
48 import android.media.MediaCommunicationManager;
49 import android.media.Session2Token;
50 import android.media.session.IActiveSessionsListener;
51 import android.media.session.IOnMediaKeyEventDispatchedListener;
52 import android.media.session.IOnMediaKeyEventSessionChangedListener;
53 import android.media.session.IOnMediaKeyListener;
54 import android.media.session.IOnVolumeKeyLongPressListener;
55 import android.media.session.ISession;
56 import android.media.session.ISession2TokensListener;
57 import android.media.session.ISessionCallback;
58 import android.media.session.ISessionManager;
59 import android.media.session.MediaController;
60 import android.media.session.MediaSession;
61 import android.media.session.MediaSessionManager;
62 import android.os.Binder;
63 import android.os.Bundle;
64 import android.os.Handler;
65 import android.os.HandlerThread;
66 import android.os.IBinder;
67 import android.os.Message;
68 import android.os.PowerExemptionManager;
69 import android.os.PowerManager;
70 import android.os.Process;
71 import android.os.RemoteCallbackList;
72 import android.os.RemoteException;
73 import android.os.ResultReceiver;
74 import android.os.ShellCallback;
75 import android.os.UserHandle;
76 import android.os.UserManager;
77 import android.provider.Settings;
78 import android.speech.RecognizerIntent;
79 import android.text.TextUtils;
80 import android.util.Log;
81 import android.util.SparseArray;
82 import android.util.SparseIntArray;
83 import android.view.KeyEvent;
84 import android.view.ViewConfiguration;
85 
86 import com.android.internal.R;
87 import com.android.internal.annotations.GuardedBy;
88 import com.android.server.LocalManagerRegistry;
89 import com.android.server.LocalServices;
90 import com.android.server.SystemService;
91 import com.android.server.Watchdog;
92 import com.android.server.Watchdog.Monitor;
93 import com.android.server.am.ActivityManagerLocal;
94 
95 import java.io.FileDescriptor;
96 import java.io.PrintWriter;
97 import java.lang.reflect.Constructor;
98 import java.lang.reflect.InvocationTargetException;
99 import java.util.ArrayList;
100 import java.util.HashMap;
101 import java.util.List;
102 
103 /**
104  * System implementation of MediaSessionManager
105  */
106 public class MediaSessionService extends SystemService implements Monitor {
107     private static final String TAG = "MediaSessionService";
108     static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
109     // Leave log for key event always.
110     static final boolean DEBUG_KEY_EVENT = true;
111 
112     private static final int WAKELOCK_TIMEOUT = 5000;
113     private static final int MEDIA_KEY_LISTENER_TIMEOUT = 1000;
114     private static final int SESSION_CREATION_LIMIT_PER_UID = 100;
115     private static final int LONG_PRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout()
116             + /* Buffer for delayed delivery of key event */ 50;
117     private static final int MULTI_TAP_TIMEOUT = ViewConfiguration.getMultiPressTimeout();
118     /**
119      * Copied from Settings.System.MEDIA_BUTTON_RECEIVER
120      */
121     private static final String MEDIA_BUTTON_RECEIVER = "media_button_receiver";
122 
123     private final Context mContext;
124     private final SessionManagerImpl mSessionManagerImpl;
125     private final MessageHandler mHandler = new MessageHandler();
126     private final PowerManager.WakeLock mMediaEventWakeLock;
127     private final NotificationManager mNotificationManager;
128     private final Object mLock = new Object();
129     private final HandlerThread mRecordThread = new HandlerThread("SessionRecordThread");
130     // Keeps the full user id for each user.
131     @GuardedBy("mLock")
132     private final SparseIntArray mFullUserIds = new SparseIntArray();
133     @GuardedBy("mLock")
134     private final SparseArray<FullUserRecord> mUserRecords = new SparseArray<FullUserRecord>();
135     @GuardedBy("mLock")
136     private final ArrayList<SessionsListenerRecord> mSessionsListeners =
137             new ArrayList<SessionsListenerRecord>();
138     @GuardedBy("mLock")
139     private final List<Session2TokensListenerRecord> mSession2TokensListenerRecords =
140             new ArrayList<>();
141 
142     private KeyguardManager mKeyguardManager;
143     private AudioManager mAudioManager;
144     private boolean mHasFeatureLeanback;
145     private ActivityManagerLocal mActivityManagerLocal;
146 
147     // The FullUserRecord of the current users. (i.e. The foreground user that isn't a profile)
148     // It's always not null after the MediaSessionService is started.
149     private FullUserRecord mCurrentFullUserRecord;
150     private MediaSessionRecord mGlobalPrioritySession;
151     private AudioPlayerStateMonitor mAudioPlayerStateMonitor;
152 
153     // Used to notify System UI and Settings when remote volume was changed.
154     @GuardedBy("mLock")
155     final RemoteCallbackList<IRemoteSessionCallback> mRemoteVolumeControllers =
156             new RemoteCallbackList<>();
157 
158     private MediaSessionPolicyProvider mCustomMediaSessionPolicyProvider;
159     private MediaKeyDispatcher mCustomMediaKeyDispatcher;
160 
161     private MediaCommunicationManager mCommunicationManager;
162     private final MediaCommunicationManager.SessionCallback mSession2TokenCallback =
163             new MediaCommunicationManager.SessionCallback() {
164                 @Override
165                 public void onSession2TokenCreated(Session2Token token) {
166                     if (DEBUG) {
167                         Log.d(TAG, "Session2 is created " + token);
168                     }
169                     MediaSession2Record record = new MediaSession2Record(token,
170                             MediaSessionService.this, mRecordThread.getLooper(), 0);
171                     synchronized (mLock) {
172                         FullUserRecord user = getFullUserRecordLocked(record.getUserId());
173                         if (user != null) {
174                             user.mPriorityStack.addSession(record);
175                         }
176                     }
177                 }
178             };
179 
MediaSessionService(Context context)180     public MediaSessionService(Context context) {
181         super(context);
182         mContext = context;
183         mSessionManagerImpl = new SessionManagerImpl();
184         PowerManager pm = mContext.getSystemService(PowerManager.class);
185         mMediaEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleMediaEvent");
186         mNotificationManager = mContext.getSystemService(NotificationManager.class);
187         mAudioManager = mContext.getSystemService(AudioManager.class);
188     }
189 
190     @Override
onStart()191     public void onStart() {
192         publishBinderService(Context.MEDIA_SESSION_SERVICE, mSessionManagerImpl);
193         Watchdog.getInstance().addMonitor(this);
194         mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
195         mAudioPlayerStateMonitor = AudioPlayerStateMonitor.getInstance(mContext);
196         mAudioPlayerStateMonitor.registerListener(
197                 (config, isRemoved) -> {
198                     if (DEBUG) {
199                         Log.d(TAG, "Audio playback is changed, config=" + config
200                                 + ", removed=" + isRemoved);
201                     }
202                     if (config.getPlayerType()
203                             == AudioPlaybackConfiguration.PLAYER_TYPE_JAM_SOUNDPOOL) {
204                         return;
205                     }
206                     synchronized (mLock) {
207                         FullUserRecord user = getFullUserRecordLocked(
208                                 UserHandle.getUserHandleForUid(config.getClientUid())
209                                         .getIdentifier());
210                         if (user != null) {
211                             user.mPriorityStack.updateMediaButtonSessionIfNeeded();
212                         }
213                     }
214                 }, null /* handler */);
215         mHasFeatureLeanback = mContext.getPackageManager().hasSystemFeature(
216                 PackageManager.FEATURE_LEANBACK);
217 
218         updateUser();
219 
220         instantiateCustomProvider(mContext.getResources().getString(
221                 R.string.config_customMediaSessionPolicyProvider));
222         instantiateCustomDispatcher(mContext.getResources().getString(
223                 R.string.config_customMediaKeyDispatcher));
224         mRecordThread.start();
225 
226         final IntentFilter filter = new IntentFilter(
227                 NotificationManager.ACTION_NOTIFICATION_LISTENER_ENABLED_CHANGED);
228         mContext.registerReceiver(mNotificationListenerEnabledChangedReceiver, filter);
229 
230         mActivityManagerLocal = LocalManagerRegistry.getManager(ActivityManagerLocal.class);
231     }
232 
233     @Override
onBootPhase(int phase)234     public void onBootPhase(int phase) {
235         super.onBootPhase(phase);
236         switch (phase) {
237             // This ensures MediaCommunicationService is started
238             case PHASE_BOOT_COMPLETED:
239                 mCommunicationManager = mContext.getSystemService(MediaCommunicationManager.class);
240                 mCommunicationManager.registerSessionCallback(new HandlerExecutor(mHandler),
241                         mSession2TokenCallback);
242                 break;
243             case PHASE_ACTIVITY_MANAGER_READY:
244                 MediaSessionDeviceConfig.initialize(mContext);
245                 break;
246         }
247     }
248 
249     private final BroadcastReceiver mNotificationListenerEnabledChangedReceiver =
250             new BroadcastReceiver() {
251                 @Override
252                 public void onReceive(Context context, Intent intent) {
253                     updateActiveSessionListeners();
254                 }
255     };
256 
isGlobalPriorityActiveLocked()257     private boolean isGlobalPriorityActiveLocked() {
258         return mGlobalPrioritySession != null && mGlobalPrioritySession.isActive();
259     }
260 
onSessionActiveStateChanged(MediaSessionRecordImpl record)261     void onSessionActiveStateChanged(MediaSessionRecordImpl record) {
262         synchronized (mLock) {
263             FullUserRecord user = getFullUserRecordLocked(record.getUserId());
264             if (user == null) {
265                 Log.w(TAG, "Unknown session updated. Ignoring.");
266                 return;
267             }
268             if (record.isSystemPriority()) {
269                 if (DEBUG_KEY_EVENT) {
270                     Log.d(TAG, "Global priority session is updated, active=" + record.isActive());
271                 }
272                 user.pushAddressedPlayerChangedLocked();
273             } else {
274                 if (!user.mPriorityStack.contains(record)) {
275                     Log.w(TAG, "Unknown session updated. Ignoring.");
276                     return;
277                 }
278                 user.mPriorityStack.onSessionActiveStateChanged(record);
279             }
280 
281             mHandler.postSessionsChanged(record);
282         }
283     }
284 
285     // Currently only media1 can become global priority session.
setGlobalPrioritySession(MediaSessionRecord record)286     void setGlobalPrioritySession(MediaSessionRecord record) {
287         synchronized (mLock) {
288             FullUserRecord user = getFullUserRecordLocked(record.getUserId());
289             if (mGlobalPrioritySession != record) {
290                 Log.d(TAG, "Global priority session is changed from " + mGlobalPrioritySession
291                         + " to " + record);
292                 mGlobalPrioritySession = record;
293                 if (user != null && user.mPriorityStack.contains(record)) {
294                     // Handle the global priority session separately.
295                     // Otherwise, it can be the media button session regardless of the active state
296                     // because it or other system components might have been the lastly played media
297                     // app.
298                     user.mPriorityStack.removeSession(record);
299                 }
300             }
301         }
302     }
303 
getActiveSessionsLocked(int userId)304     private List<MediaSessionRecord> getActiveSessionsLocked(int userId) {
305         List<MediaSessionRecord> records = new ArrayList<>();
306         if (userId == ALL.getIdentifier()) {
307             int size = mUserRecords.size();
308             for (int i = 0; i < size; i++) {
309                 records.addAll(mUserRecords.valueAt(i).mPriorityStack.getActiveSessions(userId));
310             }
311         } else {
312             FullUserRecord user = getFullUserRecordLocked(userId);
313             if (user == null) {
314                 Log.w(TAG, "getSessions failed. Unknown user " + userId);
315                 return records;
316             }
317             records.addAll(user.mPriorityStack.getActiveSessions(userId));
318         }
319 
320         // Return global priority session at the first whenever it's asked.
321         if (isGlobalPriorityActiveLocked()
322                 && (userId == ALL.getIdentifier()
323                         || userId == mGlobalPrioritySession.getUserId())) {
324             records.add(0, mGlobalPrioritySession);
325         }
326         return records;
327     }
328 
getSession2TokensLocked(int userId)329     List<Session2Token> getSession2TokensLocked(int userId) {
330         List<Session2Token> list = new ArrayList<>();
331         if (userId == ALL.getIdentifier()) {
332             int size = mUserRecords.size();
333             for (int i = 0; i < size; i++) {
334                 list.addAll(mUserRecords.valueAt(i).mPriorityStack.getSession2Tokens(userId));
335             }
336         } else {
337             FullUserRecord user = getFullUserRecordLocked(userId);
338             list.addAll(user.mPriorityStack.getSession2Tokens(userId));
339         }
340         return list;
341     }
342 
343     /**
344      * Tells the System UI and Settings app that volume has changed on an active remote session.
345      */
notifyRemoteVolumeChanged(int flags, MediaSessionRecord session)346     public void notifyRemoteVolumeChanged(int flags, MediaSessionRecord session) {
347         if (!session.isActive()) {
348             return;
349         }
350         synchronized (mLock) {
351             int size = mRemoteVolumeControllers.beginBroadcast();
352             MediaSession.Token token = session.getSessionToken();
353             for (int i = size - 1; i >= 0; i--) {
354                 try {
355                     IRemoteSessionCallback cb =
356                             mRemoteVolumeControllers.getBroadcastItem(i);
357                     cb.onVolumeChanged(token, flags);
358                 } catch (Exception e) {
359                     Log.w(TAG, "Error sending volume change.", e);
360                 }
361             }
362             mRemoteVolumeControllers.finishBroadcast();
363         }
364     }
365 
onSessionPlaybackStateChanged(MediaSessionRecordImpl record, boolean shouldUpdatePriority)366     void onSessionPlaybackStateChanged(MediaSessionRecordImpl record,
367             boolean shouldUpdatePriority) {
368         synchronized (mLock) {
369             FullUserRecord user = getFullUserRecordLocked(record.getUserId());
370             if (user == null || !user.mPriorityStack.contains(record)) {
371                 Log.d(TAG, "Unknown session changed playback state. Ignoring.");
372                 return;
373             }
374             user.mPriorityStack.onPlaybackStateChanged(record, shouldUpdatePriority);
375         }
376     }
377 
onSessionPlaybackTypeChanged(MediaSessionRecord record)378     void onSessionPlaybackTypeChanged(MediaSessionRecord record) {
379         synchronized (mLock) {
380             FullUserRecord user = getFullUserRecordLocked(record.getUserId());
381             if (user == null || !user.mPriorityStack.contains(record)) {
382                 Log.d(TAG, "Unknown session changed playback type. Ignoring.");
383                 return;
384             }
385             pushRemoteVolumeUpdateLocked(record.getUserId());
386         }
387     }
388 
389     @Override
onUserStarting(@onNull TargetUser user)390     public void onUserStarting(@NonNull TargetUser user) {
391         if (DEBUG) Log.d(TAG, "onStartUser: " + user);
392         updateUser();
393     }
394 
395     @Override
onUserSwitching(@ullable TargetUser from, @NonNull TargetUser to)396     public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
397         if (DEBUG) Log.d(TAG, "onSwitchUser: " + to);
398         updateUser();
399     }
400 
401     @Override
onUserStopped(@onNull TargetUser targetUser)402     public void onUserStopped(@NonNull TargetUser targetUser) {
403         int userId = targetUser.getUserIdentifier();
404 
405         if (DEBUG) Log.d(TAG, "onCleanupUser: " + userId);
406         synchronized (mLock) {
407             FullUserRecord user = getFullUserRecordLocked(userId);
408             if (user != null) {
409                 if (user.mFullUserId == userId) {
410                     user.destroySessionsForUserLocked(ALL.getIdentifier());
411                     mUserRecords.remove(userId);
412                 } else {
413                     user.destroySessionsForUserLocked(userId);
414                 }
415             }
416             updateUser();
417         }
418     }
419 
420     @Override
monitor()421     public void monitor() {
422         synchronized (mLock) {
423             // Check for deadlock
424         }
425     }
426 
enforcePhoneStatePermission(int pid, int uid)427     protected void enforcePhoneStatePermission(int pid, int uid) {
428         if (mContext.checkPermission(android.Manifest.permission.MODIFY_PHONE_STATE, pid, uid)
429                 != PackageManager.PERMISSION_GRANTED) {
430             throw new SecurityException("Must hold the MODIFY_PHONE_STATE permission.");
431         }
432     }
433 
onSessionDied(MediaSessionRecordImpl session)434     void onSessionDied(MediaSessionRecordImpl session) {
435         synchronized (mLock) {
436             destroySessionLocked(session);
437         }
438     }
439 
updateUser()440     private void updateUser() {
441         synchronized (mLock) {
442             UserManager manager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
443             mFullUserIds.clear();
444             List<UserHandle> allUsers = manager.getUserHandles(/*excludeDying=*/false);
445             if (allUsers != null) {
446                 for (UserHandle user : allUsers) {
447                     UserHandle parent = manager.getProfileParent(user);
448                     if (parent != null) {
449                         mFullUserIds.put(user.getIdentifier(), parent.getIdentifier());
450                     } else {
451                         mFullUserIds.put(user.getIdentifier(), user.getIdentifier());
452                         if (mUserRecords.get(user.getIdentifier()) == null) {
453                             mUserRecords.put(user.getIdentifier(),
454                                     new FullUserRecord(user.getIdentifier()));
455                         }
456                     }
457                 }
458             }
459             // Ensure that the current full user exists.
460             int currentFullUserId = ActivityManager.getCurrentUser();
461             mCurrentFullUserRecord = mUserRecords.get(currentFullUserId);
462             if (mCurrentFullUserRecord == null) {
463                 Log.w(TAG, "Cannot find FullUserInfo for the current user " + currentFullUserId);
464                 mCurrentFullUserRecord = new FullUserRecord(currentFullUserId);
465                 mUserRecords.put(currentFullUserId, mCurrentFullUserRecord);
466             }
467             mFullUserIds.put(currentFullUserId, currentFullUserId);
468         }
469     }
470 
updateActiveSessionListeners()471     private void updateActiveSessionListeners() {
472         synchronized (mLock) {
473             for (int i = mSessionsListeners.size() - 1; i >= 0; i--) {
474                 SessionsListenerRecord listener = mSessionsListeners.get(i);
475                 try {
476                     String packageName = listener.componentName == null ? null :
477                             listener.componentName.getPackageName();
478                     enforceMediaPermissions(packageName, listener.pid, listener.uid,
479                             listener.userId);
480                 } catch (SecurityException e) {
481                     Log.i(TAG, "ActiveSessionsListener " + listener.componentName
482                             + " is no longer authorized. Disconnecting.");
483                     mSessionsListeners.remove(i);
484                     try {
485                         listener.listener
486                                 .onActiveSessionsChanged(new ArrayList<MediaSession.Token>());
487                     } catch (Exception e1) {
488                         // ignore
489                     }
490                 }
491             }
492         }
493     }
494 
495     /*
496      * When a session is removed several things need to happen.
497      * 1. We need to remove it from the relevant user.
498      * 2. We need to remove it from the priority stack.
499      * 3. We need to remove it from all sessions.
500      * 4. If this is the system priority session we need to clear it.
501      * 5. We need to unlink to death from the cb binder
502      * 6. We need to tell the session to do any final cleanup (onDestroy)
503      */
destroySessionLocked(MediaSessionRecordImpl session)504     private void destroySessionLocked(MediaSessionRecordImpl session) {
505         if (DEBUG) {
506             Log.d(TAG, "Destroying " + session);
507         }
508         if (session.isClosed()) {
509             Log.w(TAG, "Destroying already destroyed session. Ignoring.");
510             return;
511         }
512 
513         FullUserRecord user = getFullUserRecordLocked(session.getUserId());
514 
515         if (user != null && session instanceof MediaSessionRecord) {
516             final int uid = session.getUid();
517             final int sessionCount = user.mUidToSessionCount.get(uid, 0);
518             if (sessionCount <= 0) {
519                 Log.w(TAG, "destroySessionLocked: sessionCount should be positive. "
520                         + "sessionCount=" + sessionCount);
521             } else {
522                 user.mUidToSessionCount.put(uid, sessionCount - 1);
523             }
524         }
525 
526         if (mGlobalPrioritySession == session) {
527             mGlobalPrioritySession = null;
528             if (session.isActive() && user != null) {
529                 user.pushAddressedPlayerChangedLocked();
530             }
531         } else {
532             if (user != null) {
533                 user.mPriorityStack.removeSession(session);
534             }
535         }
536 
537         session.close();
538         mHandler.postSessionsChanged(session);
539     }
540 
tempAllowlistTargetPkgIfPossible(int targetUid, String targetPackage, int callingPid, int callingUid, String callingPackage, String reason)541     void tempAllowlistTargetPkgIfPossible(int targetUid, String targetPackage,
542             int callingPid, int callingUid, String callingPackage, String reason) {
543         final long token = Binder.clearCallingIdentity();
544         try {
545             MediaServerUtils.enforcePackageName(callingPackage, callingUid);
546             if (targetUid != callingUid) {
547                 boolean canAllowWhileInUse = mActivityManagerLocal
548                         .canAllowWhileInUsePermissionInFgs(callingPid, callingUid, callingPackage);
549                 boolean canStartFgs = canAllowWhileInUse
550                         || mActivityManagerLocal.canStartForegroundService(callingPid, callingUid,
551                         callingPackage);
552                 Log.i(TAG, "tempAllowlistTargetPkgIfPossible callingPackage:"
553                         + callingPackage + " targetPackage:" + targetPackage
554                         + " reason:" + reason
555                         + (canAllowWhileInUse ? " [WIU]" : "")
556                         + (canStartFgs ? " [FGS]" : ""));
557                 if (canAllowWhileInUse) {
558                     mActivityManagerLocal.tempAllowWhileInUsePermissionInFgs(targetUid,
559                             MediaSessionDeviceConfig
560                                     .getMediaSessionCallbackFgsWhileInUseTempAllowDurationMs());
561                 }
562                 if (canStartFgs) {
563                     final Context userContext = mContext.createContextAsUser(
564                             UserHandle.of(UserHandle.getUserId(targetUid)), /* flags= */ 0);
565                     final PowerExemptionManager powerExemptionManager =
566                             userContext.getSystemService(
567                                     PowerExemptionManager.class);
568                     powerExemptionManager.addToTemporaryAllowList(targetPackage,
569                             PowerExemptionManager.REASON_MEDIA_SESSION_CALLBACK, reason,
570                             MediaSessionDeviceConfig.getMediaSessionCallbackFgsAllowlistDurationMs());
571                 }
572             }
573         } finally {
574             Binder.restoreCallingIdentity(token);
575         }
576     }
577 
578     /**
579      * Checks a caller's authorization to register an IRemoteControlDisplay.
580      * Authorization is granted if one of the following is true:
581      * <ul>
582      * <li>the caller has android.Manifest.permission.MEDIA_CONTENT_CONTROL
583      * permission</li>
584      * <li>the caller's listener is one of the enabled notification listeners
585      * for the caller's user</li>
586      * </ul>
587      */
enforceMediaPermissions(String packageName, int pid, int uid, int resolvedUserId)588     private void enforceMediaPermissions(String packageName, int pid, int uid,
589             int resolvedUserId) {
590         if (hasStatusBarServicePermission(pid, uid)) return;
591         if (hasMediaControlPermission(pid, uid)) return;
592 
593         if (packageName == null || !hasEnabledNotificationListener(
594                 packageName, UserHandle.getUserHandleForUid(uid), resolvedUserId)) {
595             throw new SecurityException("Missing permission to control media.");
596         }
597     }
598 
hasStatusBarServicePermission(int pid, int uid)599     private boolean hasStatusBarServicePermission(int pid, int uid) {
600         return mContext.checkPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
601                 pid, uid) == PackageManager.PERMISSION_GRANTED;
602     }
603 
enforceStatusBarServicePermission(String action, int pid, int uid)604     private void enforceStatusBarServicePermission(String action, int pid, int uid) {
605         if (!hasStatusBarServicePermission(pid, uid)) {
606             throw new SecurityException("Only System UI and Settings may " + action);
607         }
608     }
609 
hasMediaControlPermission(int pid, int uid)610     private boolean hasMediaControlPermission(int pid, int uid) {
611         // Check if it's system server or has MEDIA_CONTENT_CONTROL.
612         // Note that system server doesn't have MEDIA_CONTENT_CONTROL, so we need extra
613         // check here.
614         if (uid == Process.SYSTEM_UID || mContext.checkPermission(
615                 android.Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid)
616                 == PackageManager.PERMISSION_GRANTED) {
617             return true;
618         } else if (DEBUG) {
619             Log.d(TAG, "uid(" + uid + ") hasn't granted MEDIA_CONTENT_CONTROL");
620         }
621         return false;
622     }
623 
624     /**
625      * This checks if the given package has an enabled notification listener for the
626      * specified user. Enabled components may only operate on behalf of the user
627      * they're running as.
628      *
629      * @param packageName The package name.
630      * @param userHandle The user handle of the caller.
631      * @param forUserId The user id they're making the request on behalf of.
632      * @return True if the app has an enabled notification listener for the user, false otherwise
633      */
hasEnabledNotificationListener(String packageName, UserHandle userHandle, int forUserId)634     private boolean hasEnabledNotificationListener(String packageName,
635             UserHandle userHandle, int forUserId) {
636         if (userHandle.getIdentifier() != forUserId) {
637             // You may not access another user's content as an enabled listener.
638             return false;
639         }
640         if (DEBUG) {
641             Log.d(TAG, "Checking whether the package " + packageName + " has an"
642                     + " enabled notification listener.");
643         }
644         return mNotificationManager.hasEnabledNotificationListener(packageName, userHandle);
645     }
646 
647     /*
648      * When a session is created the following things need to happen.
649      * 1. Its callback binder needs a link to death
650      * 2. It needs to be added to all sessions.
651      * 3. It needs to be added to the priority stack.
652      * 4. It needs to be added to the relevant user record.
653      */
createSessionInternal(int callerPid, int callerUid, int userId, String callerPackageName, ISessionCallback cb, String tag, Bundle sessionInfo)654     private MediaSessionRecord createSessionInternal(int callerPid, int callerUid, int userId,
655             String callerPackageName, ISessionCallback cb, String tag, Bundle sessionInfo) {
656         synchronized (mLock) {
657             int policies = 0;
658             if (mCustomMediaSessionPolicyProvider != null) {
659                 policies = mCustomMediaSessionPolicyProvider.getSessionPoliciesForApplication(
660                         callerUid, callerPackageName);
661             }
662 
663             FullUserRecord user = getFullUserRecordLocked(userId);
664             if (user == null) {
665                 Log.w(TAG, "Request from invalid user: " +  userId + ", pkg=" + callerPackageName);
666                 throw new RuntimeException("Session request from invalid user.");
667             }
668 
669             final int sessionCount = user.mUidToSessionCount.get(callerUid, 0);
670             if (sessionCount >= SESSION_CREATION_LIMIT_PER_UID
671                     && !hasMediaControlPermission(callerPid, callerUid)) {
672                 throw new RuntimeException("Created too many sessions. count="
673                         + sessionCount + ")");
674             }
675 
676             final MediaSessionRecord session;
677             try {
678                 session = new MediaSessionRecord(callerPid, callerUid, userId,
679                         callerPackageName, cb, tag, sessionInfo, this,
680                         mRecordThread.getLooper(), policies);
681             } catch (RemoteException e) {
682                 throw new RuntimeException("Media Session owner died prematurely.", e);
683             }
684 
685             user.mUidToSessionCount.put(callerUid, sessionCount + 1);
686 
687             user.mPriorityStack.addSession(session);
688             mHandler.postSessionsChanged(session);
689 
690             if (DEBUG) {
691                 Log.d(TAG, "Created session for " + callerPackageName + " with tag " + tag);
692             }
693             return session;
694         }
695     }
696 
findIndexOfSessionsListenerLocked(IActiveSessionsListener listener)697     private int findIndexOfSessionsListenerLocked(IActiveSessionsListener listener) {
698         for (int i = mSessionsListeners.size() - 1; i >= 0; i--) {
699             if (mSessionsListeners.get(i).listener.asBinder() == listener.asBinder()) {
700                 return i;
701             }
702         }
703         return -1;
704     }
705 
findIndexOfSession2TokensListenerLocked(ISession2TokensListener listener)706     private int findIndexOfSession2TokensListenerLocked(ISession2TokensListener listener) {
707         for (int i = mSession2TokensListenerRecords.size() - 1; i >= 0; i--) {
708             if (mSession2TokensListenerRecords.get(i).listener.asBinder() == listener.asBinder()) {
709                 return i;
710             }
711         }
712         return -1;
713     }
714 
pushSession1Changed(int userId)715     private void pushSession1Changed(int userId) {
716         synchronized (mLock) {
717             FullUserRecord user = getFullUserRecordLocked(userId);
718             if (user == null) {
719                 Log.w(TAG, "pushSession1ChangedOnHandler failed. No user with id=" + userId);
720                 return;
721             }
722             List<MediaSessionRecord> records = getActiveSessionsLocked(userId);
723             int size = records.size();
724             ArrayList<MediaSession.Token> tokens = new ArrayList<>();
725             for (int i = 0; i < size; i++) {
726                 tokens.add(records.get(i).getSessionToken());
727             }
728             pushRemoteVolumeUpdateLocked(userId);
729             for (int i = mSessionsListeners.size() - 1; i >= 0; i--) {
730                 SessionsListenerRecord record = mSessionsListeners.get(i);
731                 if (record.userId == ALL.getIdentifier() || record.userId == userId) {
732                     try {
733                         record.listener.onActiveSessionsChanged(tokens);
734                     } catch (RemoteException e) {
735                         Log.w(TAG, "Dead ActiveSessionsListener in pushSessionsChanged, removing",
736                                 e);
737                         mSessionsListeners.remove(i);
738                     }
739                 }
740             }
741         }
742     }
743 
pushSession2Changed(int userId)744     void pushSession2Changed(int userId) {
745         synchronized (mLock) {
746             List<Session2Token> allSession2Tokens = getSession2TokensLocked(ALL.getIdentifier());
747             List<Session2Token> session2Tokens = getSession2TokensLocked(userId);
748 
749             for (int i = mSession2TokensListenerRecords.size() - 1; i >= 0; i--) {
750                 Session2TokensListenerRecord listenerRecord = mSession2TokensListenerRecords.get(i);
751                 try {
752                     if (listenerRecord.userId == ALL.getIdentifier()) {
753                         listenerRecord.listener.onSession2TokensChanged(allSession2Tokens);
754                     } else if (listenerRecord.userId == userId) {
755                         listenerRecord.listener.onSession2TokensChanged(session2Tokens);
756                     }
757                 } catch (RemoteException e) {
758                     Log.w(TAG, "Failed to notify Session2Token change. Removing listener.", e);
759                     mSession2TokensListenerRecords.remove(i);
760                 }
761             }
762         }
763     }
764 
pushRemoteVolumeUpdateLocked(int userId)765     private void pushRemoteVolumeUpdateLocked(int userId) {
766         FullUserRecord user = getFullUserRecordLocked(userId);
767         if (user == null) {
768             Log.w(TAG, "pushRemoteVolumeUpdateLocked failed. No user with id=" + userId);
769             return;
770         }
771 
772         synchronized (mLock) {
773             int size = mRemoteVolumeControllers.beginBroadcast();
774             MediaSessionRecordImpl record = user.mPriorityStack.getDefaultRemoteSession(userId);
775             if (record instanceof MediaSession2Record) {
776                 // TODO(jaewan): Implement
777                 return;
778             }
779             MediaSession.Token token = record == null
780                     ? null : ((MediaSessionRecord) record).getSessionToken();
781 
782             for (int i = size - 1; i >= 0; i--) {
783                 try {
784                     IRemoteSessionCallback cb =
785                             mRemoteVolumeControllers.getBroadcastItem(i);
786                     cb.onSessionChanged(token);
787                 } catch (Exception e) {
788                     Log.w(TAG, "Error sending default remote volume.", e);
789                 }
790             }
791             mRemoteVolumeControllers.finishBroadcast();
792         }
793     }
794 
795     /**
796      * Called when the media button receiver for the {@code record} is changed.
797      *
798      * @param record the media session whose media button receiver is updated.
799      */
onMediaButtonReceiverChanged(MediaSessionRecordImpl record)800     public void onMediaButtonReceiverChanged(MediaSessionRecordImpl record) {
801         synchronized (mLock) {
802             FullUserRecord user = getFullUserRecordLocked(record.getUserId());
803             MediaSessionRecordImpl mediaButtonSession =
804                     user.mPriorityStack.getMediaButtonSession();
805             if (record == mediaButtonSession) {
806                 user.rememberMediaButtonReceiverLocked(mediaButtonSession);
807             }
808         }
809     }
810 
getCallingPackageName(int uid)811     private String getCallingPackageName(int uid) {
812         String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
813         if (packages != null && packages.length > 0) {
814             return packages[0];
815         }
816         return "";
817     }
818 
dispatchVolumeKeyLongPressLocked(KeyEvent keyEvent)819     private void dispatchVolumeKeyLongPressLocked(KeyEvent keyEvent) {
820         if (mCurrentFullUserRecord.mOnVolumeKeyLongPressListener == null) {
821             return;
822         }
823         try {
824             mCurrentFullUserRecord.mOnVolumeKeyLongPressListener.onVolumeKeyLongPress(keyEvent);
825         } catch (RemoteException e) {
826             Log.w(TAG, "Failed to send " + keyEvent + " to volume key long-press listener");
827         }
828     }
829 
getFullUserRecordLocked(int userId)830     private FullUserRecord getFullUserRecordLocked(int userId) {
831         int fullUserId = mFullUserIds.get(userId, -1);
832         if (fullUserId < 0) {
833             return null;
834         }
835         return mUserRecords.get(fullUserId);
836     }
837 
getMediaSessionRecordLocked(MediaSession.Token sessionToken)838     private MediaSessionRecord getMediaSessionRecordLocked(MediaSession.Token sessionToken) {
839         FullUserRecord user = getFullUserRecordLocked(
840                 UserHandle.getUserHandleForUid(sessionToken.getUid()).getIdentifier());
841         if (user != null) {
842             return user.mPriorityStack.getMediaSessionRecord(sessionToken);
843         }
844         return null;
845     }
846 
instantiateCustomDispatcher(String componentName)847     private void instantiateCustomDispatcher(String componentName) {
848         synchronized (mLock) {
849             mCustomMediaKeyDispatcher = null;
850 
851             try {
852                 if (componentName != null && !TextUtils.isEmpty(componentName)) {
853                     Class customDispatcherClass = Class.forName(componentName);
854                     Constructor constructor =
855                             customDispatcherClass.getDeclaredConstructor(Context.class);
856                     mCustomMediaKeyDispatcher =
857                             (MediaKeyDispatcher) constructor.newInstance(mContext);
858                 }
859             } catch (ClassNotFoundException | InstantiationException | InvocationTargetException
860                     | IllegalAccessException | NoSuchMethodException e) {
861                 mCustomMediaKeyDispatcher = null;
862                 Log.w(TAG, "Encountered problem while using reflection", e);
863             }
864         }
865     }
866 
instantiateCustomProvider(String componentName)867     private void instantiateCustomProvider(String componentName) {
868         synchronized (mLock) {
869             mCustomMediaSessionPolicyProvider = null;
870 
871             try {
872                 if (componentName != null && !TextUtils.isEmpty(componentName)) {
873                     Class customProviderClass = Class.forName(componentName);
874                     Constructor constructor =
875                             customProviderClass.getDeclaredConstructor(Context.class);
876                     mCustomMediaSessionPolicyProvider =
877                             (MediaSessionPolicyProvider) constructor.newInstance(mContext);
878                 }
879             } catch (ClassNotFoundException | InstantiationException | InvocationTargetException
880                     | IllegalAccessException | NoSuchMethodException e) {
881                 Log.w(TAG, "Encountered problem while using reflection", e);
882             }
883         }
884     }
885 
886     /**
887      * Information about a full user and its corresponding managed profiles.
888      *
889      * <p>Since the full user runs together with its managed profiles, a user wouldn't differentiate
890      * them when they press a media/volume button. So keeping media sessions for them in one
891      * place makes more sense and increases the readability.</p>
892      * <p>The contents of this object is guarded by {@link #mLock}.
893      */
894     final class FullUserRecord implements MediaSessionStack.OnMediaButtonSessionChangedListener {
895         private final int mFullUserId;
896         private final ContentResolver mContentResolver;
897         private final MediaSessionStack mPriorityStack;
898         private final HashMap<IBinder, OnMediaKeyEventDispatchedListenerRecord>
899                 mOnMediaKeyEventDispatchedListeners = new HashMap<>();
900         private final HashMap<IBinder, OnMediaKeyEventSessionChangedListenerRecord>
901                 mOnMediaKeyEventSessionChangedListeners = new HashMap<>();
902         private final SparseIntArray mUidToSessionCount = new SparseIntArray();
903 
904         private MediaButtonReceiverHolder mLastMediaButtonReceiverHolder;
905 
906         private IOnVolumeKeyLongPressListener mOnVolumeKeyLongPressListener;
907         private int mOnVolumeKeyLongPressListenerUid;
908 
909         private IOnMediaKeyListener mOnMediaKeyListener;
910         private int mOnMediaKeyListenerUid;
911 
FullUserRecord(int fullUserId)912         FullUserRecord(int fullUserId) {
913             mFullUserId = fullUserId;
914             mContentResolver = mContext.createContextAsUser(UserHandle.of(mFullUserId), 0)
915                     .getContentResolver();
916             mPriorityStack = new MediaSessionStack(mAudioPlayerStateMonitor, this);
917             // Restore the remembered media button receiver before the boot.
918             String mediaButtonReceiverInfo = Settings.Secure.getString(mContentResolver,
919                     MEDIA_BUTTON_RECEIVER);
920             mLastMediaButtonReceiverHolder =
921                     MediaButtonReceiverHolder.unflattenFromString(
922                             mContext, mediaButtonReceiverInfo);
923         }
924 
destroySessionsForUserLocked(int userId)925         public void destroySessionsForUserLocked(int userId) {
926             List<MediaSessionRecord> sessions = mPriorityStack.getPriorityList(false, userId);
927             for (MediaSessionRecord session : sessions) {
928                 destroySessionLocked(session);
929             }
930         }
931 
addOnMediaKeyEventDispatchedListenerLocked( IOnMediaKeyEventDispatchedListener listener, int uid)932         public void addOnMediaKeyEventDispatchedListenerLocked(
933                 IOnMediaKeyEventDispatchedListener listener, int uid) {
934             IBinder cbBinder = listener.asBinder();
935             OnMediaKeyEventDispatchedListenerRecord cr =
936                     new OnMediaKeyEventDispatchedListenerRecord(listener, uid);
937             mOnMediaKeyEventDispatchedListeners.put(cbBinder, cr);
938             try {
939                 cbBinder.linkToDeath(cr, 0);
940             } catch (RemoteException e) {
941                 Log.w(TAG, "Failed to add listener", e);
942                 mOnMediaKeyEventDispatchedListeners.remove(cbBinder);
943             }
944         }
945 
removeOnMediaKeyEventDispatchedListenerLocked( IOnMediaKeyEventDispatchedListener listener)946         public void removeOnMediaKeyEventDispatchedListenerLocked(
947                 IOnMediaKeyEventDispatchedListener listener) {
948             IBinder cbBinder = listener.asBinder();
949             OnMediaKeyEventDispatchedListenerRecord cr =
950                     mOnMediaKeyEventDispatchedListeners.remove(cbBinder);
951             cbBinder.unlinkToDeath(cr, 0);
952         }
953 
addOnMediaKeyEventSessionChangedListenerLocked( IOnMediaKeyEventSessionChangedListener listener, int uid)954         public void addOnMediaKeyEventSessionChangedListenerLocked(
955                 IOnMediaKeyEventSessionChangedListener listener, int uid) {
956             IBinder cbBinder = listener.asBinder();
957             OnMediaKeyEventSessionChangedListenerRecord cr =
958                     new OnMediaKeyEventSessionChangedListenerRecord(listener, uid);
959             mOnMediaKeyEventSessionChangedListeners.put(cbBinder, cr);
960             try {
961                 cbBinder.linkToDeath(cr, 0);
962             } catch (RemoteException e) {
963                 Log.w(TAG, "Failed to add listener", e);
964                 mOnMediaKeyEventSessionChangedListeners.remove(cbBinder);
965             }
966         }
967 
removeOnMediaKeyEventSessionChangedListener( IOnMediaKeyEventSessionChangedListener listener)968         public void removeOnMediaKeyEventSessionChangedListener(
969                 IOnMediaKeyEventSessionChangedListener listener) {
970             IBinder cbBinder = listener.asBinder();
971             OnMediaKeyEventSessionChangedListenerRecord cr =
972                     mOnMediaKeyEventSessionChangedListeners.remove(cbBinder);
973             cbBinder.unlinkToDeath(cr, 0);
974         }
975 
dumpLocked(PrintWriter pw, String prefix)976         public void dumpLocked(PrintWriter pw, String prefix) {
977             pw.print(prefix + "Record for full_user=" + mFullUserId);
978             // Dump managed profile user ids associated with this user.
979             int size = mFullUserIds.size();
980             for (int i = 0; i < size; i++) {
981                 if (mFullUserIds.keyAt(i) != mFullUserIds.valueAt(i)
982                         && mFullUserIds.valueAt(i) == mFullUserId) {
983                     pw.print(", profile_user=" + mFullUserIds.keyAt(i));
984                 }
985             }
986             pw.println();
987             String indent = prefix + "  ";
988             pw.println(indent + "Volume key long-press listener: " + mOnVolumeKeyLongPressListener);
989             pw.println(indent + "Volume key long-press listener package: "
990                     + getCallingPackageName(mOnVolumeKeyLongPressListenerUid));
991             pw.println(indent + "Media key listener: " + mOnMediaKeyListener);
992             pw.println(indent + "Media key listener package: "
993                     + getCallingPackageName(mOnMediaKeyListenerUid));
994             pw.println(indent + "OnMediaKeyEventDispatchedListener: added "
995                     + mOnMediaKeyEventDispatchedListeners.size() + " listener(s)");
996             for (OnMediaKeyEventDispatchedListenerRecord cr
997                     : mOnMediaKeyEventDispatchedListeners.values()) {
998                 pw.println(indent + "  from " + getCallingPackageName(cr.uid));
999             }
1000             pw.println(indent + "OnMediaKeyEventSessionChangedListener: added "
1001                     + mOnMediaKeyEventSessionChangedListeners.size() + " listener(s)");
1002             for (OnMediaKeyEventSessionChangedListenerRecord cr
1003                     : mOnMediaKeyEventSessionChangedListeners.values()) {
1004                 pw.println(indent + "  from " + getCallingPackageName(cr.uid));
1005             }
1006             pw.println(indent + "Last MediaButtonReceiver: " + mLastMediaButtonReceiverHolder);
1007             mPriorityStack.dump(pw, indent);
1008         }
1009 
1010         @Override
onMediaButtonSessionChanged(MediaSessionRecordImpl oldMediaButtonSession, MediaSessionRecordImpl newMediaButtonSession)1011         public void onMediaButtonSessionChanged(MediaSessionRecordImpl oldMediaButtonSession,
1012                 MediaSessionRecordImpl newMediaButtonSession) {
1013             if (DEBUG_KEY_EVENT) {
1014                 Log.d(TAG, "Media button session is changed to " + newMediaButtonSession);
1015             }
1016             synchronized (mLock) {
1017                 if (oldMediaButtonSession != null) {
1018                     mHandler.postSessionsChanged(oldMediaButtonSession);
1019                 }
1020                 if (newMediaButtonSession != null) {
1021                     rememberMediaButtonReceiverLocked(newMediaButtonSession);
1022                     mHandler.postSessionsChanged(newMediaButtonSession);
1023                 }
1024                 pushAddressedPlayerChangedLocked();
1025             }
1026         }
1027 
1028         // Remember media button receiver and keep it in the persistent storage.
rememberMediaButtonReceiverLocked(MediaSessionRecordImpl record)1029         public void rememberMediaButtonReceiverLocked(MediaSessionRecordImpl record) {
1030             if (record instanceof MediaSession2Record) {
1031                 // TODO(jaewan): Implement
1032                 return;
1033             }
1034             MediaSessionRecord sessionRecord = (MediaSessionRecord) record;
1035             mLastMediaButtonReceiverHolder = sessionRecord.getMediaButtonReceiver();
1036             String mediaButtonReceiverInfo = (mLastMediaButtonReceiverHolder == null)
1037                     ? "" : mLastMediaButtonReceiverHolder.flattenToString();
1038             Settings.Secure.putString(mContentResolver,
1039                     MEDIA_BUTTON_RECEIVER,
1040                     mediaButtonReceiverInfo);
1041         }
1042 
pushAddressedPlayerChangedLocked( IOnMediaKeyEventSessionChangedListener callback)1043         private void pushAddressedPlayerChangedLocked(
1044                 IOnMediaKeyEventSessionChangedListener callback) {
1045             try {
1046                 MediaSessionRecordImpl mediaButtonSession = getMediaButtonSessionLocked();
1047                 if (mediaButtonSession != null) {
1048                     if (mediaButtonSession instanceof MediaSessionRecord) {
1049                         MediaSessionRecord session1 = (MediaSessionRecord) mediaButtonSession;
1050                         callback.onMediaKeyEventSessionChanged(session1.getPackageName(),
1051                                 session1.getSessionToken());
1052                     } else {
1053                         // TODO(jaewan): Implement
1054                     }
1055                 } else if (mCurrentFullUserRecord.mLastMediaButtonReceiverHolder != null) {
1056                     String packageName =
1057                             mCurrentFullUserRecord.mLastMediaButtonReceiverHolder.getPackageName();
1058                     callback.onMediaKeyEventSessionChanged(packageName, null);
1059                 } else {
1060                     callback.onMediaKeyEventSessionChanged("", null);
1061                 }
1062             } catch (RemoteException e) {
1063                 Log.w(TAG, "Failed to pushAddressedPlayerChangedLocked", e);
1064             }
1065         }
1066 
pushAddressedPlayerChangedLocked()1067         private void pushAddressedPlayerChangedLocked() {
1068             for (OnMediaKeyEventSessionChangedListenerRecord cr
1069                     : mOnMediaKeyEventSessionChangedListeners.values()) {
1070                 pushAddressedPlayerChangedLocked(cr.callback);
1071             }
1072         }
1073 
getMediaButtonSessionLocked()1074         private MediaSessionRecordImpl getMediaButtonSessionLocked() {
1075             return isGlobalPriorityActiveLocked()
1076                     ? mGlobalPrioritySession : mPriorityStack.getMediaButtonSession();
1077         }
1078 
1079         final class OnMediaKeyEventDispatchedListenerRecord implements IBinder.DeathRecipient {
1080             public final IOnMediaKeyEventDispatchedListener callback;
1081             public final int uid;
1082 
OnMediaKeyEventDispatchedListenerRecord(IOnMediaKeyEventDispatchedListener callback, int uid)1083             OnMediaKeyEventDispatchedListenerRecord(IOnMediaKeyEventDispatchedListener callback,
1084                     int uid) {
1085                 this.callback = callback;
1086                 this.uid = uid;
1087             }
1088 
1089             @Override
binderDied()1090             public void binderDied() {
1091                 synchronized (mLock) {
1092                     mOnMediaKeyEventDispatchedListeners.remove(callback.asBinder());
1093                 }
1094             }
1095         }
1096 
1097         final class OnMediaKeyEventSessionChangedListenerRecord implements IBinder.DeathRecipient {
1098             public final IOnMediaKeyEventSessionChangedListener callback;
1099             public final int uid;
1100 
OnMediaKeyEventSessionChangedListenerRecord( IOnMediaKeyEventSessionChangedListener callback, int uid)1101             OnMediaKeyEventSessionChangedListenerRecord(
1102                     IOnMediaKeyEventSessionChangedListener callback, int uid) {
1103                 this.callback = callback;
1104                 this.uid = uid;
1105             }
1106 
1107             @Override
binderDied()1108             public void binderDied() {
1109                 synchronized (mLock) {
1110                     mOnMediaKeyEventSessionChangedListeners.remove(callback.asBinder());
1111                 }
1112             }
1113         }
1114     }
1115 
1116     final class SessionsListenerRecord implements IBinder.DeathRecipient {
1117         public final IActiveSessionsListener listener;
1118         public final ComponentName componentName;
1119         public final int userId;
1120         public final int pid;
1121         public final int uid;
1122 
SessionsListenerRecord(IActiveSessionsListener listener, ComponentName componentName, int userId, int pid, int uid)1123         SessionsListenerRecord(IActiveSessionsListener listener,
1124                 ComponentName componentName,
1125                 int userId, int pid, int uid) {
1126             this.listener = listener;
1127             this.componentName = componentName;
1128             this.userId = userId;
1129             this.pid = pid;
1130             this.uid = uid;
1131         }
1132 
1133         @Override
binderDied()1134         public void binderDied() {
1135             synchronized (mLock) {
1136                 mSessionsListeners.remove(this);
1137             }
1138         }
1139     }
1140 
1141     final class Session2TokensListenerRecord implements IBinder.DeathRecipient {
1142         public final ISession2TokensListener listener;
1143         public final int userId;
1144 
Session2TokensListenerRecord(ISession2TokensListener listener, int userId)1145         Session2TokensListenerRecord(ISession2TokensListener listener,
1146                 int userId) {
1147             this.listener = listener;
1148             this.userId = userId;
1149         }
1150 
1151         @Override
binderDied()1152         public void binderDied() {
1153             synchronized (mLock) {
1154                 mSession2TokensListenerRecords.remove(this);
1155             }
1156         }
1157     }
1158 
1159     class SessionManagerImpl extends ISessionManager.Stub {
1160         private static final String EXTRA_WAKELOCK_ACQUIRED =
1161                 "android.media.AudioService.WAKELOCK_ACQUIRED";
1162         private static final int WAKELOCK_RELEASE_ON_FINISHED = 1980; // magic number
1163 
1164         private KeyEventHandler mMediaKeyEventHandler =
1165                 new KeyEventHandler(KeyEventHandler.KEY_TYPE_MEDIA);
1166         private KeyEventHandler mVolumeKeyEventHandler =
1167                 new KeyEventHandler(KeyEventHandler.KEY_TYPE_VOLUME);
1168 
1169         @Override
onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver)1170         public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
1171                 String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
1172             String[] packageNames =
1173                     mContext.getPackageManager().getPackagesForUid(Binder.getCallingUid());
1174             String packageName = packageNames != null && packageNames.length > 0
1175                     ? packageNames[0]
1176                     : "com.android.shell"; // We should not need this branch, but defaulting to the
1177                                            // current shell package name for robustness. See
1178                                            // b/227109905.
1179             new MediaShellCommand(packageName)
1180                     .exec(this, in, out, err, args, callback, resultReceiver);
1181         }
1182 
1183         @Override
createSession(String packageName, ISessionCallback cb, String tag, Bundle sessionInfo, int userId)1184         public ISession createSession(String packageName, ISessionCallback cb, String tag,
1185                 Bundle sessionInfo, int userId) throws RemoteException {
1186             final int pid = Binder.getCallingPid();
1187             final int uid = Binder.getCallingUid();
1188             final long token = Binder.clearCallingIdentity();
1189             try {
1190                 MediaServerUtils.enforcePackageName(packageName, uid);
1191                 int resolvedUserId = handleIncomingUser(pid, uid, userId, packageName);
1192                 if (cb == null) {
1193                     throw new IllegalArgumentException("Controller callback cannot be null");
1194                 }
1195                 MediaSessionRecord session = createSessionInternal(
1196                         pid, uid, resolvedUserId, packageName, cb, tag, sessionInfo);
1197                 if (session == null) {
1198                     throw new IllegalStateException("Failed to create a new session record");
1199                 }
1200                 ISession sessionBinder = session.getSessionBinder();
1201                 if (sessionBinder == null) {
1202                     throw new IllegalStateException("Invalid session record");
1203                 }
1204                 return sessionBinder;
1205             } catch (Exception e) {
1206                 Log.w(TAG, "Exception in creating a new session", e);
1207                 throw e;
1208             } finally {
1209                 Binder.restoreCallingIdentity(token);
1210             }
1211         }
1212 
1213         @Override
getSessions(ComponentName componentName, int userId)1214         public List<MediaSession.Token> getSessions(ComponentName componentName, int userId) {
1215             final int pid = Binder.getCallingPid();
1216             final int uid = Binder.getCallingUid();
1217             final long token = Binder.clearCallingIdentity();
1218 
1219             try {
1220                 int resolvedUserId = verifySessionsRequest(componentName, userId, pid, uid);
1221                 ArrayList<MediaSession.Token> tokens = new ArrayList<>();
1222                 synchronized (mLock) {
1223                     List<MediaSessionRecord> records = getActiveSessionsLocked(resolvedUserId);
1224                     for (MediaSessionRecord record : records) {
1225                         tokens.add(record.getSessionToken());
1226                     }
1227                 }
1228                 return tokens;
1229             } finally {
1230                 Binder.restoreCallingIdentity(token);
1231             }
1232         }
1233 
1234         @Override
getMediaKeyEventSession(final String packageName)1235         public MediaSession.Token getMediaKeyEventSession(final String packageName) {
1236             final int pid = Binder.getCallingPid();
1237             final int uid = Binder.getCallingUid();
1238             final UserHandle userHandle = UserHandle.getUserHandleForUid(uid);
1239             final int userId = userHandle.getIdentifier();
1240             final long token = Binder.clearCallingIdentity();
1241             try {
1242                 MediaServerUtils.enforcePackageName(packageName, uid);
1243                 enforceMediaPermissions(packageName, pid, uid, userId);
1244 
1245                 MediaSessionRecordImpl record;
1246                 synchronized (mLock) {
1247                     FullUserRecord user = getFullUserRecordLocked(userId);
1248                     if (user == null) {
1249                         Log.w(TAG, "No matching user record to get the media key event session"
1250                                 + ", userId=" + userId);
1251                         return null;
1252                     }
1253                     record = user.getMediaButtonSessionLocked();
1254                 }
1255                 if (record instanceof MediaSessionRecord) {
1256                     return ((MediaSessionRecord) record).getSessionToken();
1257                 }
1258                 //TODO: Handle media session 2 case
1259                 return null;
1260             } finally {
1261                 Binder.restoreCallingIdentity(token);
1262             }
1263         }
1264 
1265         @Override
getMediaKeyEventSessionPackageName(final String packageName)1266         public String getMediaKeyEventSessionPackageName(final String packageName) {
1267             final int pid = Binder.getCallingPid();
1268             final int uid = Binder.getCallingUid();
1269             final UserHandle userHandle = UserHandle.getUserHandleForUid(uid);
1270             final int userId = userHandle.getIdentifier();
1271             final long token = Binder.clearCallingIdentity();
1272             try {
1273                 MediaServerUtils.enforcePackageName(packageName, uid);
1274                 enforceMediaPermissions(packageName, pid, uid, userId);
1275 
1276                 MediaSessionRecordImpl record;
1277                 synchronized (mLock) {
1278                     FullUserRecord user = getFullUserRecordLocked(userId);
1279                     if (user == null) {
1280                         Log.w(TAG, "No matching user record to get the media key event session"
1281                                 + " package , userId=" + userId);
1282                         return "";
1283                     }
1284                     record = user.getMediaButtonSessionLocked();
1285                     if (record instanceof MediaSessionRecord) {
1286                         return record.getPackageName();
1287                     //TODO: Handle media session 2 case
1288                     } else if (user.mLastMediaButtonReceiverHolder != null) {
1289                         return user.mLastMediaButtonReceiverHolder.getPackageName();
1290                     }
1291                 }
1292                 return "";
1293             } finally {
1294                 Binder.restoreCallingIdentity(token);
1295             }
1296         }
1297 
1298         @Override
addSessionsListener(IActiveSessionsListener listener, ComponentName componentName, int userId)1299         public void addSessionsListener(IActiveSessionsListener listener,
1300                 ComponentName componentName, int userId) throws RemoteException {
1301             if (listener == null) {
1302                 Log.w(TAG, "addSessionsListener: listener is null, ignoring");
1303                 return;
1304             }
1305             final int pid = Binder.getCallingPid();
1306             final int uid = Binder.getCallingUid();
1307             final long token = Binder.clearCallingIdentity();
1308 
1309             try {
1310                 int resolvedUserId = verifySessionsRequest(componentName, userId, pid, uid);
1311                 synchronized (mLock) {
1312                     int index = findIndexOfSessionsListenerLocked(listener);
1313                     if (index != -1) {
1314                         Log.w(TAG, "ActiveSessionsListener is already added, ignoring");
1315                         return;
1316                     }
1317                     SessionsListenerRecord record = new SessionsListenerRecord(listener,
1318                             componentName, resolvedUserId, pid, uid);
1319                     try {
1320                         listener.asBinder().linkToDeath(record, 0);
1321                     } catch (RemoteException e) {
1322                         Log.e(TAG, "ActiveSessionsListener is dead, ignoring it", e);
1323                         return;
1324                     }
1325                     mSessionsListeners.add(record);
1326                 }
1327             } finally {
1328                 Binder.restoreCallingIdentity(token);
1329             }
1330         }
1331 
1332         @Override
removeSessionsListener(IActiveSessionsListener listener)1333         public void removeSessionsListener(IActiveSessionsListener listener)
1334                 throws RemoteException {
1335             synchronized (mLock) {
1336                 int index = findIndexOfSessionsListenerLocked(listener);
1337                 if (index != -1) {
1338                     SessionsListenerRecord record = mSessionsListeners.remove(index);
1339                     try {
1340                         record.listener.asBinder().unlinkToDeath(record, 0);
1341                     } catch (Exception e) {
1342                         // ignore exceptions, the record is being removed
1343                     }
1344                 }
1345             }
1346         }
1347 
1348         @Override
addSession2TokensListener(ISession2TokensListener listener, int userId)1349         public void addSession2TokensListener(ISession2TokensListener listener,
1350                 int userId) {
1351             if (listener == null) {
1352                 Log.w(TAG, "addSession2TokensListener: listener is null, ignoring");
1353                 return;
1354             }
1355             final int pid = Binder.getCallingPid();
1356             final int uid = Binder.getCallingUid();
1357             final long token = Binder.clearCallingIdentity();
1358 
1359             try {
1360                 // Check that they can make calls on behalf of the user and get the final user id.
1361                 int resolvedUserId = handleIncomingUser(pid, uid, userId, null);
1362                 synchronized (mLock) {
1363                     int index = findIndexOfSession2TokensListenerLocked(listener);
1364                     if (index >= 0) {
1365                         Log.w(TAG, "addSession2TokensListener: "
1366                                 + "listener is already added, ignoring");
1367                         return;
1368                     }
1369                     mSession2TokensListenerRecords.add(
1370                             new Session2TokensListenerRecord(listener, resolvedUserId));
1371                 }
1372             } finally {
1373                 Binder.restoreCallingIdentity(token);
1374             }
1375         }
1376 
1377         @Override
removeSession2TokensListener(ISession2TokensListener listener)1378         public void removeSession2TokensListener(ISession2TokensListener listener) {
1379             final int pid = Binder.getCallingPid();
1380             final int uid = Binder.getCallingUid();
1381             final long token = Binder.clearCallingIdentity();
1382 
1383             try {
1384                 synchronized (mLock) {
1385                     int index = findIndexOfSession2TokensListenerLocked(listener);
1386                     if (index >= 0) {
1387                         Session2TokensListenerRecord listenerRecord =
1388                                 mSession2TokensListenerRecords.remove(index);
1389                         try {
1390                             listenerRecord.listener.asBinder().unlinkToDeath(listenerRecord, 0);
1391                         } catch (Exception e) {
1392                             // Ignore exception.
1393                         }
1394                     }
1395                 }
1396             } finally {
1397                 Binder.restoreCallingIdentity(token);
1398             }
1399         }
1400 
1401         /**
1402          * Dispaches media key events. This is called when the foreground activity didn't handled
1403          * the incoming media key event.
1404          * <p>
1405          * Handles the dispatching of the media button events to one of the
1406          * registered listeners, or if there was none, broadcast an
1407          * ACTION_MEDIA_BUTTON intent to the rest of the system.
1408          *
1409          * @param packageName The caller package
1410          * @param asSystemService {@code true} if the event sent to the session came from the
1411          *          service instead of the app process. This helps sessions to distinguish between
1412          *          the key injection by the app and key events from the hardware devices. Should be
1413          *          used only when the hardware key events aren't handled by foreground activity.
1414          *          {@code false} otherwise to tell session about the real caller.
1415          * @param keyEvent a non-null KeyEvent whose key code is one of the
1416          *            supported media buttons
1417          * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held
1418          *            while this key event is dispatched.
1419          */
1420         @Override
dispatchMediaKeyEvent(String packageName, boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock)1421         public void dispatchMediaKeyEvent(String packageName, boolean asSystemService,
1422                 KeyEvent keyEvent, boolean needWakeLock) {
1423             if (keyEvent == null || !KeyEvent.isMediaSessionKey(keyEvent.getKeyCode())) {
1424                 Log.w(TAG, "Attempted to dispatch null or non-media key event.");
1425                 return;
1426             }
1427 
1428             final int pid = Binder.getCallingPid();
1429             final int uid = Binder.getCallingUid();
1430             final long token = Binder.clearCallingIdentity();
1431             try {
1432                 if (DEBUG) {
1433                     Log.d(TAG, "dispatchMediaKeyEvent, pkg=" + packageName + " pid=" + pid
1434                             + ", uid=" + uid + ", asSystem=" + asSystemService + ", event="
1435                             + keyEvent);
1436                 }
1437                 if (!isUserSetupComplete()) {
1438                     // Global media key handling can have the side-effect of starting new
1439                     // activities which is undesirable while setup is in progress.
1440                     Log.i(TAG, "Not dispatching media key event because user "
1441                             + "setup is in progress.");
1442                     return;
1443                 }
1444 
1445                 synchronized (mLock) {
1446                     boolean isGlobalPriorityActive = isGlobalPriorityActiveLocked();
1447                     if (isGlobalPriorityActive && uid != Process.SYSTEM_UID) {
1448                         // Prevent dispatching key event through reflection while the global
1449                         // priority session is active.
1450                         Log.i(TAG, "Only the system can dispatch media key event "
1451                                 + "to the global priority session.");
1452                         return;
1453                     }
1454                     if (!isGlobalPriorityActive) {
1455                         if (mCurrentFullUserRecord.mOnMediaKeyListener != null) {
1456                             if (DEBUG_KEY_EVENT) {
1457                                 Log.d(TAG, "Send " + keyEvent + " to the media key listener");
1458                             }
1459                             try {
1460                                 mCurrentFullUserRecord.mOnMediaKeyListener.onMediaKey(keyEvent,
1461                                         new MediaKeyListenerResultReceiver(packageName, pid, uid,
1462                                                 asSystemService, keyEvent, needWakeLock));
1463                                 return;
1464                             } catch (RemoteException e) {
1465                                 Log.w(TAG, "Failed to send " + keyEvent
1466                                         + " to the media key listener");
1467                             }
1468                         }
1469                     }
1470                     if (isGlobalPriorityActive) {
1471                         dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
1472                                 keyEvent, needWakeLock);
1473                     } else {
1474                         mMediaKeyEventHandler.handleMediaKeyEventLocked(packageName, pid, uid,
1475                                 asSystemService, keyEvent, needWakeLock);
1476                     }
1477                 }
1478             } finally {
1479                 Binder.restoreCallingIdentity(token);
1480             }
1481         }
1482 
1483         /**
1484          * Dispatches media key events to session as system service. This is used only when the
1485          * foreground activity has set
1486          * {@link android.app.Activity#setMediaController(MediaController)} and a media key was
1487          * pressed.
1488          *
1489          * @param packageName The caller's package name, obtained by Context#getPackageName()
1490          * @param sessionToken token for the session that the controller is pointing to
1491          * @param keyEvent media key event
1492          * @see #dispatchVolumeKeyEvent
1493          */
1494         @Override
dispatchMediaKeyEventToSessionAsSystemService(String packageName, KeyEvent keyEvent, MediaSession.Token sessionToken)1495         public boolean dispatchMediaKeyEventToSessionAsSystemService(String packageName,
1496                 KeyEvent keyEvent, MediaSession.Token sessionToken) {
1497             final int pid = Binder.getCallingPid();
1498             final int uid = Binder.getCallingUid();
1499             final long token = Binder.clearCallingIdentity();
1500             try {
1501                 synchronized (mLock) {
1502                     MediaSessionRecord record = getMediaSessionRecordLocked(sessionToken);
1503                     if (DEBUG_KEY_EVENT) {
1504                         Log.d(TAG, "dispatchMediaKeyEventToSessionAsSystemService, pkg="
1505                                 + packageName + ", pid=" + pid + ", uid=" + uid + ", sessionToken="
1506                                 + sessionToken + ", event=" + keyEvent + ", session=" + record);
1507                     }
1508                     if (record == null) {
1509                         Log.w(TAG, "Failed to find session to dispatch key event.");
1510                         return false;
1511                     }
1512                     return record.sendMediaButton(packageName, pid, uid, true /* asSystemService */,
1513                             keyEvent, 0, null);
1514                 }
1515             } finally {
1516                 Binder.restoreCallingIdentity(token);
1517             }
1518         }
1519 
1520         @Override
addOnMediaKeyEventDispatchedListener( final IOnMediaKeyEventDispatchedListener listener)1521         public void addOnMediaKeyEventDispatchedListener(
1522                 final IOnMediaKeyEventDispatchedListener listener) {
1523             if (listener == null) {
1524                 Log.w(TAG, "addOnMediaKeyEventDispatchedListener: listener is null, ignoring");
1525                 return;
1526             }
1527             final int pid = Binder.getCallingPid();
1528             final int uid = Binder.getCallingUid();
1529             final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
1530             final long token = Binder.clearCallingIdentity();
1531             try {
1532                 if (!hasMediaControlPermission(pid, uid)) {
1533                     throw new SecurityException("MEDIA_CONTENT_CONTROL permission is required to"
1534                             + "  add MediaKeyEventDispatchedListener");
1535                 }
1536                 synchronized (mLock) {
1537                     FullUserRecord user = getFullUserRecordLocked(userId);
1538                     if (user == null || user.mFullUserId != userId) {
1539                         Log.w(TAG, "Only the full user can add the listener"
1540                                 + ", userId=" + userId);
1541                         return;
1542                     }
1543                     user.addOnMediaKeyEventDispatchedListenerLocked(listener, uid);
1544                     Log.d(TAG, "The MediaKeyEventDispatchedListener (" + listener.asBinder()
1545                             + ") is added by " + getCallingPackageName(uid));
1546                 }
1547             } finally {
1548                 Binder.restoreCallingIdentity(token);
1549             }
1550         }
1551 
1552         @Override
removeOnMediaKeyEventDispatchedListener( final IOnMediaKeyEventDispatchedListener listener)1553         public void removeOnMediaKeyEventDispatchedListener(
1554                 final IOnMediaKeyEventDispatchedListener listener) {
1555             if (listener == null) {
1556                 Log.w(TAG, "removeOnMediaKeyEventDispatchedListener: listener is null, ignoring");
1557                 return;
1558             }
1559             final int pid = Binder.getCallingPid();
1560             final int uid = Binder.getCallingUid();
1561             final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
1562             final long token = Binder.clearCallingIdentity();
1563             try {
1564                 if (!hasMediaControlPermission(pid, uid)) {
1565                     throw new SecurityException("MEDIA_CONTENT_CONTROL permission is required to"
1566                             + "  remove MediaKeyEventDispatchedListener");
1567                 }
1568                 synchronized (mLock) {
1569                     FullUserRecord user = getFullUserRecordLocked(userId);
1570                     if (user == null || user.mFullUserId != userId) {
1571                         Log.w(TAG, "Only the full user can remove the listener"
1572                                 + ", userId=" + userId);
1573                         return;
1574                     }
1575                     user.removeOnMediaKeyEventDispatchedListenerLocked(listener);
1576                     Log.d(TAG, "The MediaKeyEventDispatchedListener (" + listener.asBinder()
1577                             + ") is removed by " + getCallingPackageName(uid));
1578                 }
1579             } finally {
1580                 Binder.restoreCallingIdentity(token);
1581             }
1582         }
1583 
1584         @Override
addOnMediaKeyEventSessionChangedListener( final IOnMediaKeyEventSessionChangedListener listener, final String packageName)1585         public void addOnMediaKeyEventSessionChangedListener(
1586                 final IOnMediaKeyEventSessionChangedListener listener,
1587                 final String packageName) {
1588             if (listener == null) {
1589                 Log.w(TAG, "addOnMediaKeyEventSessionChangedListener: listener is null, ignoring");
1590                 return;
1591             }
1592 
1593             final int pid = Binder.getCallingPid();
1594             final int uid = Binder.getCallingUid();
1595             final UserHandle userHandle = UserHandle.getUserHandleForUid(uid);
1596             final int userId = userHandle.getIdentifier();
1597             final long token = Binder.clearCallingIdentity();
1598             try {
1599                 MediaServerUtils.enforcePackageName(packageName, uid);
1600                 enforceMediaPermissions(packageName, pid, uid, userId);
1601 
1602                 synchronized (mLock) {
1603                     FullUserRecord user = getFullUserRecordLocked(userId);
1604                     if (user == null || user.mFullUserId != userId) {
1605                         Log.w(TAG, "Only the full user can add the listener"
1606                                 + ", userId=" + userId);
1607                         return;
1608                     }
1609                     user.addOnMediaKeyEventSessionChangedListenerLocked(listener, uid);
1610                     Log.d(TAG, "The MediaKeyEventSessionChangedListener (" + listener.asBinder()
1611                             + ") is added by " + packageName);
1612                 }
1613             } finally {
1614                 Binder.restoreCallingIdentity(token);
1615             }
1616         }
1617 
1618         @Override
removeOnMediaKeyEventSessionChangedListener( final IOnMediaKeyEventSessionChangedListener listener)1619         public void removeOnMediaKeyEventSessionChangedListener(
1620                 final IOnMediaKeyEventSessionChangedListener listener) {
1621             if (listener == null) {
1622                 Log.w(TAG, "removeOnMediaKeyEventSessionChangedListener: listener is null,"
1623                         + " ignoring");
1624                 return;
1625             }
1626 
1627             final int pid = Binder.getCallingPid();
1628             final int uid = Binder.getCallingUid();
1629             final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
1630             final long token = Binder.clearCallingIdentity();
1631             try {
1632                 synchronized (mLock) {
1633                     FullUserRecord user = getFullUserRecordLocked(userId);
1634                     if (user == null || user.mFullUserId != userId) {
1635                         Log.w(TAG, "Only the full user can remove the listener"
1636                                 + ", userId=" + userId);
1637                         return;
1638                     }
1639                     user.removeOnMediaKeyEventSessionChangedListener(listener);
1640                     Log.d(TAG, "The MediaKeyEventSessionChangedListener (" + listener.asBinder()
1641                             + ") is removed by " + getCallingPackageName(uid));
1642                 }
1643             } finally {
1644                 Binder.restoreCallingIdentity(token);
1645             }
1646         }
1647 
1648         @Override
setOnVolumeKeyLongPressListener(IOnVolumeKeyLongPressListener listener)1649         public void setOnVolumeKeyLongPressListener(IOnVolumeKeyLongPressListener listener) {
1650             final int pid = Binder.getCallingPid();
1651             final int uid = Binder.getCallingUid();
1652             final long token = Binder.clearCallingIdentity();
1653             try {
1654                 // Enforce SET_VOLUME_KEY_LONG_PRESS_LISTENER permission.
1655                 if (mContext.checkPermission(
1656                         android.Manifest.permission.SET_VOLUME_KEY_LONG_PRESS_LISTENER, pid, uid)
1657                         != PackageManager.PERMISSION_GRANTED) {
1658                     throw new SecurityException("Must hold the SET_VOLUME_KEY_LONG_PRESS_LISTENER"
1659                             + " permission.");
1660                 }
1661 
1662                 synchronized (mLock) {
1663                     int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
1664                     FullUserRecord user = getFullUserRecordLocked(userId);
1665                     if (user == null || user.mFullUserId != userId) {
1666                         Log.w(TAG, "Only the full user can set the volume key long-press listener"
1667                                 + ", userId=" + userId);
1668                         return;
1669                     }
1670                     if (user.mOnVolumeKeyLongPressListener != null
1671                             && user.mOnVolumeKeyLongPressListenerUid != uid) {
1672                         Log.w(TAG, "The volume key long-press listener cannot be reset"
1673                                 + " by another app , mOnVolumeKeyLongPressListener="
1674                                 + user.mOnVolumeKeyLongPressListenerUid
1675                                 + ", uid=" + uid);
1676                         return;
1677                     }
1678 
1679                     user.mOnVolumeKeyLongPressListener = listener;
1680                     user.mOnVolumeKeyLongPressListenerUid = uid;
1681 
1682                     Log.d(TAG, "The volume key long-press listener "
1683                             + listener + " is set by " + getCallingPackageName(uid));
1684 
1685                     if (user.mOnVolumeKeyLongPressListener != null) {
1686                         try {
1687                             user.mOnVolumeKeyLongPressListener.asBinder().linkToDeath(
1688                                     new IBinder.DeathRecipient() {
1689                                         @Override
1690                                         public void binderDied() {
1691                                             synchronized (mLock) {
1692                                                 user.mOnVolumeKeyLongPressListener = null;
1693                                             }
1694                                         }
1695                                     }, 0);
1696                         } catch (RemoteException e) {
1697                             Log.w(TAG, "Failed to set death recipient "
1698                                     + user.mOnVolumeKeyLongPressListener);
1699                             user.mOnVolumeKeyLongPressListener = null;
1700                         }
1701                     }
1702                 }
1703             } finally {
1704                 Binder.restoreCallingIdentity(token);
1705             }
1706         }
1707 
1708         @Override
setOnMediaKeyListener(IOnMediaKeyListener listener)1709         public void setOnMediaKeyListener(IOnMediaKeyListener listener) {
1710             final int pid = Binder.getCallingPid();
1711             final int uid = Binder.getCallingUid();
1712             final long token = Binder.clearCallingIdentity();
1713             try {
1714                 // Enforce SET_MEDIA_KEY_LISTENER permission.
1715                 if (mContext.checkPermission(
1716                         android.Manifest.permission.SET_MEDIA_KEY_LISTENER, pid, uid)
1717                         != PackageManager.PERMISSION_GRANTED) {
1718                     throw new SecurityException("Must hold the SET_MEDIA_KEY_LISTENER permission.");
1719                 }
1720 
1721                 synchronized (mLock) {
1722                     int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
1723                     FullUserRecord user = getFullUserRecordLocked(userId);
1724                     if (user == null || user.mFullUserId != userId) {
1725                         Log.w(TAG, "Only the full user can set the media key listener"
1726                                 + ", userId=" + userId);
1727                         return;
1728                     }
1729                     if (user.mOnMediaKeyListener != null && user.mOnMediaKeyListenerUid != uid) {
1730                         Log.w(TAG, "The media key listener cannot be reset by another app. "
1731                                 + ", mOnMediaKeyListenerUid=" + user.mOnMediaKeyListenerUid
1732                                 + ", uid=" + uid);
1733                         return;
1734                     }
1735 
1736                     user.mOnMediaKeyListener = listener;
1737                     user.mOnMediaKeyListenerUid = uid;
1738 
1739                     Log.d(TAG, "The media key listener " + user.mOnMediaKeyListener
1740                             + " is set by " + getCallingPackageName(uid));
1741 
1742                     if (user.mOnMediaKeyListener != null) {
1743                         try {
1744                             user.mOnMediaKeyListener.asBinder().linkToDeath(
1745                                     new IBinder.DeathRecipient() {
1746                                         @Override
1747                                         public void binderDied() {
1748                                             synchronized (mLock) {
1749                                                 user.mOnMediaKeyListener = null;
1750                                             }
1751                                         }
1752                                     }, 0);
1753                         } catch (RemoteException e) {
1754                             Log.w(TAG, "Failed to set death recipient " + user.mOnMediaKeyListener);
1755                             user.mOnMediaKeyListener = null;
1756                         }
1757                     }
1758                 }
1759             } finally {
1760                 Binder.restoreCallingIdentity(token);
1761             }
1762         }
1763 
1764         /**
1765          * Dispatches volume key events. This is called when the foreground activity didn't handle
1766          * the incoming volume key event.
1767          * <p>
1768          * Handles the dispatching of the volume button events to one of the
1769          * registered listeners. If there's a volume key long-press listener and
1770          * there's no active global priority session, long-presses will be sent to the
1771          * long-press listener instead of adjusting volume.
1772          *
1773          * @param packageName The caller's package name, obtained by Context#getPackageName()
1774          * @param opPackageName The caller's op package name, obtained by Context#getOpPackageName()
1775          * @param asSystemService {@code true} if the event sent to the session as if it was come
1776          *          from the system service instead of the app process. This helps sessions to
1777          *          distinguish between the key injection by the app and key events from the
1778          *          hardware devices. Should be used only when the volume key events aren't handled
1779          *          by foreground activity. {@code false} otherwise to tell session about the real
1780          *          caller.
1781          * @param keyEvent a non-null KeyEvent whose key code is one of the
1782          *            {@link KeyEvent#KEYCODE_VOLUME_UP},
1783          *            {@link KeyEvent#KEYCODE_VOLUME_DOWN},
1784          *            or {@link KeyEvent#KEYCODE_VOLUME_MUTE}.
1785          * @param stream stream type to adjust volume.
1786          * @param musicOnly true if both UI and haptic feedback aren't needed when adjusting volume.
1787          * @see #dispatchVolumeKeyEventToSessionAsSystemService
1788          */
1789         @Override
dispatchVolumeKeyEvent(String packageName, String opPackageName, boolean asSystemService, KeyEvent keyEvent, int stream, boolean musicOnly)1790         public void dispatchVolumeKeyEvent(String packageName, String opPackageName,
1791                 boolean asSystemService, KeyEvent keyEvent, int stream, boolean musicOnly) {
1792             if (keyEvent == null
1793                     || (keyEvent.getKeyCode() != KeyEvent.KEYCODE_VOLUME_UP
1794                     && keyEvent.getKeyCode() != KeyEvent.KEYCODE_VOLUME_DOWN
1795                     && keyEvent.getKeyCode() != KeyEvent.KEYCODE_VOLUME_MUTE)) {
1796                 Log.w(TAG, "Attempted to dispatch null or non-volume key event.");
1797                 return;
1798             }
1799 
1800             final int pid = Binder.getCallingPid();
1801             final int uid = Binder.getCallingUid();
1802             final long token = Binder.clearCallingIdentity();
1803 
1804             if (DEBUG_KEY_EVENT) {
1805                 Log.d(TAG, "dispatchVolumeKeyEvent, pkg=" + packageName
1806                         + ", opPkg=" + opPackageName + ", pid=" + pid + ", uid=" + uid
1807                         + ", asSystem=" + asSystemService + ", event=" + keyEvent
1808                         + ", stream=" + stream + ", musicOnly=" + musicOnly);
1809             }
1810 
1811             try {
1812                 synchronized (mLock) {
1813                     if (isGlobalPriorityActiveLocked()) {
1814                         dispatchVolumeKeyEventLocked(packageName, opPackageName, pid, uid,
1815                                 asSystemService, keyEvent, stream, musicOnly);
1816                     } else {
1817                         // TODO: Consider the case when both volume up and down keys are pressed
1818                         //       at the same time.
1819                         mVolumeKeyEventHandler.handleVolumeKeyEventLocked(packageName, pid, uid,
1820                                 asSystemService, keyEvent, opPackageName, stream, musicOnly);
1821                     }
1822                 }
1823             } finally {
1824                 Binder.restoreCallingIdentity(token);
1825             }
1826         }
1827 
dispatchVolumeKeyEventLocked(String packageName, String opPackageName, int pid, int uid, boolean asSystemService, KeyEvent keyEvent, int stream, boolean musicOnly)1828         private void dispatchVolumeKeyEventLocked(String packageName, String opPackageName, int pid,
1829                 int uid, boolean asSystemService, KeyEvent keyEvent, int stream,
1830                 boolean musicOnly) {
1831             boolean down = keyEvent.getAction() == KeyEvent.ACTION_DOWN;
1832             boolean up = keyEvent.getAction() == KeyEvent.ACTION_UP;
1833             int direction = 0;
1834             boolean isMute = false;
1835             switch (keyEvent.getKeyCode()) {
1836                 case KeyEvent.KEYCODE_VOLUME_UP:
1837                     direction = AudioManager.ADJUST_RAISE;
1838                     break;
1839                 case KeyEvent.KEYCODE_VOLUME_DOWN:
1840                     direction = AudioManager.ADJUST_LOWER;
1841                     break;
1842                 case KeyEvent.KEYCODE_VOLUME_MUTE:
1843                     isMute = true;
1844                     break;
1845             }
1846             if (down || up) {
1847                 int flags = AudioManager.FLAG_FROM_KEY;
1848                 if (!musicOnly) {
1849                     // These flags are consistent with the home screen
1850                     if (up) {
1851                         flags |= AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_VIBRATE;
1852                     } else {
1853                         flags |= AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_VIBRATE;
1854                     }
1855                 }
1856                 if (direction != 0) {
1857                     // If this is action up we want to send a beep for non-music events
1858                     if (up) {
1859                         direction = 0;
1860                     }
1861                     dispatchAdjustVolumeLocked(packageName, opPackageName, pid, uid,
1862                             asSystemService, stream, direction, flags, musicOnly);
1863                 } else if (isMute) {
1864                     if (down && keyEvent.getRepeatCount() == 0) {
1865                         dispatchAdjustVolumeLocked(packageName, opPackageName, pid, uid,
1866                                 asSystemService, stream, AudioManager.ADJUST_TOGGLE_MUTE, flags,
1867                                 musicOnly);
1868                     }
1869                 }
1870             }
1871         }
1872 
1873         /**
1874          * Dispatches volume key events to session as system service. This is used only when the
1875          * foreground activity has set
1876          * {@link android.app.Activity#setMediaController(MediaController)} and a hardware volume
1877          * key was pressed.
1878          *
1879          * @param packageName The caller's package name, obtained by Context#getPackageName()
1880          * @param opPackageName The caller's op package name, obtained by Context#getOpPackageName()
1881          * @param sessionToken token for the session that the controller is pointing to
1882          * @param keyEvent volume key event
1883          * @see #dispatchVolumeKeyEvent
1884          */
1885         @Override
dispatchVolumeKeyEventToSessionAsSystemService(String packageName, String opPackageName, KeyEvent keyEvent, MediaSession.Token sessionToken)1886         public void dispatchVolumeKeyEventToSessionAsSystemService(String packageName,
1887                 String opPackageName, KeyEvent keyEvent, MediaSession.Token sessionToken) {
1888             int pid = Binder.getCallingPid();
1889             int uid = Binder.getCallingUid();
1890             final long token = Binder.clearCallingIdentity();
1891             try {
1892                 synchronized (mLock) {
1893                     MediaSessionRecord record = getMediaSessionRecordLocked(sessionToken);
1894                     if (DEBUG_KEY_EVENT) {
1895                         Log.d(TAG, "dispatchVolumeKeyEventToSessionAsSystemService, pkg="
1896                                 + packageName + ", opPkg=" + opPackageName + ", pid=" + pid
1897                                 + ", uid=" + uid + ", sessionToken=" + sessionToken + ", event="
1898                                 + keyEvent + ", session=" + record);
1899                     }
1900                     if (record == null) {
1901                         Log.w(TAG, "Failed to find session to dispatch key event, token="
1902                                 + sessionToken + ". Fallbacks to the default handling.");
1903                         dispatchVolumeKeyEventLocked(packageName, opPackageName, pid, uid, true,
1904                                 keyEvent, AudioManager.USE_DEFAULT_STREAM_TYPE, false);
1905                         return;
1906                     }
1907                     switch (keyEvent.getAction()) {
1908                         case KeyEvent.ACTION_DOWN: {
1909                             int direction = 0;
1910                             switch (keyEvent.getKeyCode()) {
1911                                 case KeyEvent.KEYCODE_VOLUME_UP:
1912                                     direction = AudioManager.ADJUST_RAISE;
1913                                     break;
1914                                 case KeyEvent.KEYCODE_VOLUME_DOWN:
1915                                     direction = AudioManager.ADJUST_LOWER;
1916                                     break;
1917                                 case KeyEvent.KEYCODE_VOLUME_MUTE:
1918                                     direction = AudioManager.ADJUST_TOGGLE_MUTE;
1919                                     break;
1920                             }
1921                             record.adjustVolume(packageName, opPackageName, pid, uid,
1922                                     true /* asSystemService */, direction,
1923                                     AudioManager.FLAG_SHOW_UI, false /* useSuggested */);
1924                             break;
1925                         }
1926 
1927                         case KeyEvent.ACTION_UP: {
1928                             final int flags =
1929                                     AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_VIBRATE
1930                                             | AudioManager.FLAG_FROM_KEY;
1931                             record.adjustVolume(packageName, opPackageName, pid, uid,
1932                                     true /* asSystemService */, 0, flags, false /* useSuggested */);
1933                         }
1934                     }
1935                 }
1936             } finally {
1937                 Binder.restoreCallingIdentity(token);
1938             }
1939         }
1940 
1941         @Override
dispatchAdjustVolume(String packageName, String opPackageName, int suggestedStream, int delta, int flags)1942         public void dispatchAdjustVolume(String packageName, String opPackageName,
1943                 int suggestedStream, int delta, int flags) {
1944             final int pid = Binder.getCallingPid();
1945             final int uid = Binder.getCallingUid();
1946             final long token = Binder.clearCallingIdentity();
1947             try {
1948                 synchronized (mLock) {
1949                     dispatchAdjustVolumeLocked(packageName, opPackageName, pid, uid, false,
1950                             suggestedStream, delta, flags, false);
1951                 }
1952             } finally {
1953                 Binder.restoreCallingIdentity(token);
1954             }
1955         }
1956 
1957         @Override
registerRemoteSessionCallback(IRemoteSessionCallback rvc)1958         public void registerRemoteSessionCallback(IRemoteSessionCallback rvc) {
1959             final int pid = Binder.getCallingPid();
1960             final int uid = Binder.getCallingUid();
1961             final long token = Binder.clearCallingIdentity();
1962             synchronized (mLock) {
1963                 try {
1964                     enforceStatusBarServicePermission("listen for volume changes", pid, uid);
1965                     mRemoteVolumeControllers.register(rvc);
1966                 } finally {
1967                     Binder.restoreCallingIdentity(token);
1968                 }
1969             }
1970         }
1971 
1972         @Override
unregisterRemoteSessionCallback(IRemoteSessionCallback rvc)1973         public void unregisterRemoteSessionCallback(IRemoteSessionCallback rvc) {
1974             final int pid = Binder.getCallingPid();
1975             final int uid = Binder.getCallingUid();
1976             final long token = Binder.clearCallingIdentity();
1977             synchronized (mLock) {
1978                 try {
1979                     enforceStatusBarServicePermission("listen for volume changes", pid, uid);
1980                     mRemoteVolumeControllers.unregister(rvc);
1981                 } finally {
1982                     Binder.restoreCallingIdentity(token);
1983                 }
1984             }
1985         }
1986 
1987         @Override
isGlobalPriorityActive()1988         public boolean isGlobalPriorityActive() {
1989             synchronized (mLock) {
1990                 return isGlobalPriorityActiveLocked();
1991             }
1992         }
1993 
1994         @Override
dump(FileDescriptor fd, final PrintWriter pw, String[] args)1995         public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
1996             if (!MediaServerUtils.checkDumpPermission(mContext, TAG, pw)) return;
1997 
1998             pw.println("MEDIA SESSION SERVICE (dumpsys media_session)");
1999             pw.println();
2000 
2001             synchronized (mLock) {
2002                 pw.println(mSessionsListeners.size() + " sessions listeners.");
2003                 pw.println("Global priority session is " + mGlobalPrioritySession);
2004                 if (mGlobalPrioritySession != null) {
2005                     mGlobalPrioritySession.dump(pw, "  ");
2006                 }
2007                 pw.println("User Records:");
2008                 int count = mUserRecords.size();
2009                 for (int i = 0; i < count; i++) {
2010                     mUserRecords.valueAt(i).dumpLocked(pw, "");
2011                 }
2012                 mAudioPlayerStateMonitor.dump(mContext, pw, "");
2013             }
2014             MediaSessionDeviceConfig.dump(pw, "");
2015         }
2016 
2017         /**
2018          * Returns if the controller's package is trusted (i.e. has either MEDIA_CONTENT_CONTROL
2019          * permission or an enabled notification listener)
2020          *
2021          * @param controllerPackageName package name of the controller app
2022          * @param controllerPid pid of the controller app
2023          * @param controllerUid uid of the controller app
2024          */
2025         @Override
isTrusted(String controllerPackageName, int controllerPid, int controllerUid)2026         public boolean isTrusted(String controllerPackageName, int controllerPid,
2027                 int controllerUid) {
2028             final int uid = Binder.getCallingUid();
2029             final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
2030             if (LocalServices.getService(PackageManagerInternal.class)
2031                     .filterAppAccess(controllerPackageName, uid, userId)) {
2032                 // The controllerPackageName is not visible to the caller.
2033                 return false;
2034             }
2035             final long token = Binder.clearCallingIdentity();
2036             try {
2037                 // Don't perform check between controllerPackageName and controllerUid.
2038                 // When an (activity|service) runs on the another apps process by specifying
2039                 // android:process in the AndroidManifest.xml, then PID and UID would have the
2040                 // running process' information instead of the (activity|service) that has created
2041                 // MediaController.
2042                 // Note that we can use Context#getOpPackageName() instead of
2043                 // Context#getPackageName() for getting package name that matches with the PID/UID,
2044                 // but it doesn't tell which package has created the MediaController, so useless.
2045                 return hasMediaControlPermission(controllerPid, controllerUid)
2046                         || hasEnabledNotificationListener(
2047                                 userId, controllerPackageName, controllerUid);
2048             } finally {
2049                 Binder.restoreCallingIdentity(token);
2050             }
2051         }
2052 
2053         @Override
setCustomMediaKeyDispatcher(String name)2054         public void setCustomMediaKeyDispatcher(String name) {
2055             instantiateCustomDispatcher(name);
2056         }
2057 
2058         @Override
setCustomMediaSessionPolicyProvider(String name)2059         public void setCustomMediaSessionPolicyProvider(String name) {
2060             instantiateCustomProvider(name);
2061         }
2062 
2063         @Override
hasCustomMediaKeyDispatcher(String componentName)2064         public boolean hasCustomMediaKeyDispatcher(String componentName) {
2065             return mCustomMediaKeyDispatcher == null ? false
2066                     : TextUtils.equals(componentName,
2067                             mCustomMediaKeyDispatcher.getClass().getName());
2068         }
2069 
2070         @Override
hasCustomMediaSessionPolicyProvider(String componentName)2071         public boolean hasCustomMediaSessionPolicyProvider(String componentName) {
2072             return mCustomMediaSessionPolicyProvider == null ? false
2073                     : TextUtils.equals(componentName,
2074                             mCustomMediaSessionPolicyProvider.getClass().getName());
2075         }
2076 
2077         @Override
getSessionPolicies(MediaSession.Token token)2078         public int getSessionPolicies(MediaSession.Token token) {
2079             synchronized (mLock) {
2080                 MediaSessionRecord record = getMediaSessionRecordLocked(token);
2081                 if (record != null) {
2082                     return record.getSessionPolicies();
2083                 }
2084             }
2085             return 0;
2086         }
2087 
2088         @Override
setSessionPolicies(MediaSession.Token token, int policies)2089         public void setSessionPolicies(MediaSession.Token token, int policies) {
2090             final long callingIdentityToken = Binder.clearCallingIdentity();
2091             try {
2092                 synchronized (mLock) {
2093                     MediaSessionRecord record = getMediaSessionRecordLocked(token);
2094                     FullUserRecord user = getFullUserRecordLocked(record.getUserId());
2095                     if (record != null && user != null) {
2096                         record.setSessionPolicies(policies);
2097                         user.mPriorityStack.updateMediaButtonSessionBySessionPolicyChange(record);
2098                     }
2099                 }
2100             } finally {
2101                 Binder.restoreCallingIdentity(callingIdentityToken);
2102             }
2103         }
2104 
2105         // For MediaSession
verifySessionsRequest(ComponentName componentName, int userId, final int pid, final int uid)2106         private int verifySessionsRequest(ComponentName componentName, int userId, final int pid,
2107                 final int uid) {
2108             String packageName = null;
2109             if (componentName != null) {
2110                 // If they gave us a component name verify they own the
2111                 // package
2112                 packageName = componentName.getPackageName();
2113                 MediaServerUtils.enforcePackageName(packageName, uid);
2114             }
2115             // Check that they can make calls on behalf of the user and get the final user id
2116             int resolvedUserId = handleIncomingUser(pid, uid, userId, packageName);
2117             // Check if they have the permissions or their component is enabled for the user
2118             // they're calling from.
2119             enforceMediaPermissions(packageName, pid, uid, resolvedUserId);
2120             return resolvedUserId;
2121         }
2122 
2123         // Handles incoming user by checking whether the caller has permission to access the
2124         // given user id's information or not. Permission is not necessary if the given user id is
2125         // equal to the caller's user id, but if not, the caller needs to have the
2126         // INTERACT_ACROSS_USERS_FULL permission. Otherwise, a security exception will be thrown.
2127         // The return value will be the given user id, unless the given user id is
2128         // UserHandle.CURRENT, which will return the ActivityManager.getCurrentUser() value instead.
handleIncomingUser(int pid, int uid, int userId, String packageName)2129         private int handleIncomingUser(int pid, int uid, int userId, String packageName) {
2130             int callingUserId = UserHandle.getUserHandleForUid(uid).getIdentifier();
2131             if (userId == callingUserId) {
2132                 return userId;
2133             }
2134 
2135             boolean canInteractAcrossUsersFull = mContext.checkPermission(
2136                     INTERACT_ACROSS_USERS_FULL, pid, uid) == PackageManager.PERMISSION_GRANTED;
2137             if (canInteractAcrossUsersFull) {
2138                 if (userId == CURRENT.getIdentifier()) {
2139                     return ActivityManager.getCurrentUser();
2140                 }
2141                 return userId;
2142             }
2143 
2144             throw new SecurityException("Permission denied while calling from " + packageName
2145                     + " with user id: " + userId + "; Need to run as either the calling user id ("
2146                     + callingUserId + "), or with " + INTERACT_ACROSS_USERS_FULL + " permission");
2147         }
2148 
hasEnabledNotificationListener(int callingUserId, String controllerPackageName, int controllerUid)2149         private boolean hasEnabledNotificationListener(int callingUserId,
2150                 String controllerPackageName, int controllerUid) {
2151             int controllerUserId = UserHandle.getUserHandleForUid(controllerUid).getIdentifier();
2152             if (callingUserId != controllerUserId) {
2153                 // Enabled notification listener only works within the same user.
2154                 return false;
2155             }
2156             // Verify whether package name and controller UID.
2157             // It will indirectly check whether the caller has obtained the package name and UID
2158             // via ControllerInfo or with the valid package name visibility.
2159             try {
2160                 int actualControllerUid = mContext.getPackageManager().getPackageUidAsUser(
2161                         controllerPackageName,
2162                         UserHandle.getUserId(controllerUid));
2163                 if (controllerUid != actualControllerUid) {
2164                     Log.w(TAG, "Failed to check enabled notification listener. Package name and"
2165                             + " UID doesn't match");
2166                     return false;
2167                 }
2168             } catch (PackageManager.NameNotFoundException e) {
2169                 Log.w(TAG, "Failed to check enabled notification listener. Package name doesn't"
2170                         + " exist");
2171                 return false;
2172             }
2173 
2174             if (mNotificationManager.hasEnabledNotificationListener(controllerPackageName,
2175                     UserHandle.getUserHandleForUid(controllerUid))) {
2176                 return true;
2177             }
2178             if (DEBUG) {
2179                 Log.d(TAG, controllerPackageName + " (uid=" + controllerUid
2180                         + ") doesn't have an enabled notification listener");
2181             }
2182             return false;
2183         }
2184 
dispatchAdjustVolumeLocked(String packageName, String opPackageName, int pid, int uid, boolean asSystemService, int suggestedStream, int direction, int flags, boolean musicOnly)2185         private void dispatchAdjustVolumeLocked(String packageName, String opPackageName, int pid,
2186                 int uid, boolean asSystemService, int suggestedStream, int direction, int flags,
2187                 boolean musicOnly) {
2188             MediaSessionRecordImpl session = isGlobalPriorityActiveLocked() ? mGlobalPrioritySession
2189                     : mCurrentFullUserRecord.mPriorityStack.getDefaultVolumeSession();
2190 
2191             boolean preferSuggestedStream = false;
2192             if (isValidLocalStreamType(suggestedStream)
2193                     && AudioSystem.isStreamActive(suggestedStream, 0)) {
2194                 preferSuggestedStream = true;
2195             }
2196             if (session == null || preferSuggestedStream) {
2197                 if (DEBUG_KEY_EVENT) {
2198                     Log.d(TAG, "Adjusting suggestedStream=" + suggestedStream + " by " + direction
2199                             + ". flags=" + flags + ", preferSuggestedStream="
2200                             + preferSuggestedStream + ", session=" + session);
2201                 }
2202                 if (musicOnly && !AudioSystem.isStreamActive(AudioManager.STREAM_MUSIC, 0)) {
2203                     if (DEBUG_KEY_EVENT) {
2204                         Log.d(TAG, "Nothing is playing on the music stream. Skipping volume event,"
2205                                 + " flags=" + flags);
2206                     }
2207                     return;
2208                 }
2209 
2210                 // Execute mAudioService.adjustSuggestedStreamVolume() on
2211                 // handler thread of MediaSessionService.
2212                 // This will release the MediaSessionService.mLock sooner and avoid
2213                 // a potential deadlock between MediaSessionService.mLock and
2214                 // ActivityManagerService lock.
2215                 mHandler.post(new Runnable() {
2216                     @Override
2217                     public void run() {
2218                         final String callingOpPackageName;
2219                         final int callingUid;
2220                         final int callingPid;
2221                         if (asSystemService) {
2222                             callingOpPackageName = mContext.getOpPackageName();
2223                             callingUid = Process.myUid();
2224                             callingPid = Process.myPid();
2225                         } else {
2226                             callingOpPackageName = opPackageName;
2227                             callingUid = uid;
2228                             callingPid = pid;
2229                         }
2230                         try {
2231                             mAudioManager.adjustSuggestedStreamVolumeForUid(suggestedStream,
2232                                     direction, flags, callingOpPackageName, callingUid, callingPid,
2233                                     getContext().getApplicationInfo().targetSdkVersion);
2234                         } catch (SecurityException | IllegalArgumentException e) {
2235                             Log.e(TAG, "Cannot adjust volume: direction=" + direction
2236                                     + ", suggestedStream=" + suggestedStream + ", flags=" + flags
2237                                     + ", packageName=" + packageName + ", uid=" + uid
2238                                     + ", asSystemService=" + asSystemService, e);
2239                         }
2240                     }
2241                 });
2242             } else {
2243                 if (DEBUG_KEY_EVENT) {
2244                     Log.d(TAG, "Adjusting " + session + " by " + direction + ". flags="
2245                             + flags + ", suggestedStream=" + suggestedStream
2246                             + ", preferSuggestedStream=" + preferSuggestedStream);
2247                 }
2248                 session.adjustVolume(packageName, opPackageName, pid, uid, asSystemService,
2249                         direction, flags, true);
2250             }
2251         }
2252 
dispatchMediaKeyEventLocked(String packageName, int pid, int uid, boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock)2253         private void dispatchMediaKeyEventLocked(String packageName, int pid, int uid,
2254                 boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock) {
2255             if (mCurrentFullUserRecord.getMediaButtonSessionLocked()
2256                     instanceof MediaSession2Record) {
2257                 // TODO(jaewan): Make MediaSession2 to receive media key event
2258                 return;
2259             }
2260             MediaSessionRecord session = null;
2261             MediaButtonReceiverHolder mediaButtonReceiverHolder = null;
2262 
2263             if (mCustomMediaKeyDispatcher != null) {
2264                 MediaSession.Token token = mCustomMediaKeyDispatcher.getMediaSession(
2265                         keyEvent, uid, asSystemService);
2266                 if (token != null) {
2267                     session = getMediaSessionRecordLocked(token);
2268                 }
2269 
2270                 if (session == null) {
2271                     PendingIntent pi = mCustomMediaKeyDispatcher.getMediaButtonReceiver(keyEvent,
2272                             uid, asSystemService);
2273                     if (pi != null) {
2274                         mediaButtonReceiverHolder =
2275                                 MediaButtonReceiverHolder.create(
2276                                         mCurrentFullUserRecord.mFullUserId, pi, "");
2277                     }
2278                 }
2279             }
2280 
2281             if (session == null && mediaButtonReceiverHolder == null) {
2282                 session = (MediaSessionRecord) mCurrentFullUserRecord.getMediaButtonSessionLocked();
2283 
2284                 if (session == null) {
2285                     mediaButtonReceiverHolder =
2286                             mCurrentFullUserRecord.mLastMediaButtonReceiverHolder;
2287                 }
2288             }
2289 
2290             if (session != null) {
2291                 if (DEBUG_KEY_EVENT) {
2292                     Log.d(TAG, "Sending " + keyEvent + " to " + session);
2293                 }
2294                 if (needWakeLock) {
2295                     mKeyEventReceiver.acquireWakeLockLocked();
2296                 }
2297                 // If we don't need a wakelock use -1 as the id so we won't release it later.
2298                 session.sendMediaButton(packageName, pid, uid, asSystemService, keyEvent,
2299                         needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
2300                         mKeyEventReceiver);
2301                 try {
2302                     for (FullUserRecord.OnMediaKeyEventDispatchedListenerRecord cr
2303                             : mCurrentFullUserRecord.mOnMediaKeyEventDispatchedListeners.values()) {
2304                         cr.callback.onMediaKeyEventDispatched(
2305                                 keyEvent, session.getPackageName(), session.getSessionToken());
2306                     }
2307                 } catch (RemoteException e) {
2308                     Log.w(TAG, "Failed to send callback", e);
2309                 }
2310             } else if (mediaButtonReceiverHolder != null) {
2311                 if (needWakeLock) {
2312                     mKeyEventReceiver.acquireWakeLockLocked();
2313                 }
2314                 String callingPackageName =
2315                         (asSystemService) ? mContext.getPackageName() : packageName;
2316                 boolean sent = mediaButtonReceiverHolder.send(
2317                         mContext, keyEvent, callingPackageName,
2318                         needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1, mKeyEventReceiver,
2319                         mHandler,
2320                         MediaSessionDeviceConfig.getMediaButtonReceiverFgsAllowlistDurationMs());
2321                 if (sent) {
2322                     String pkgName = mediaButtonReceiverHolder.getPackageName();
2323                     for (FullUserRecord.OnMediaKeyEventDispatchedListenerRecord cr
2324                             : mCurrentFullUserRecord
2325                             .mOnMediaKeyEventDispatchedListeners.values()) {
2326                         try {
2327                             cr.callback.onMediaKeyEventDispatched(keyEvent, pkgName, null);
2328                         } catch (RemoteException e) {
2329                             Log.w(TAG, "Failed notify key event dispatch, uid=" + cr.uid, e);
2330                         }
2331                     }
2332                 }
2333             }
2334         }
2335 
startVoiceInput(boolean needWakeLock)2336         private void startVoiceInput(boolean needWakeLock) {
2337             Intent voiceIntent = null;
2338             // select which type of search to launch:
2339             // - screen on and device unlocked: action is ACTION_WEB_SEARCH
2340             // - device locked or screen off: action is
2341             // ACTION_VOICE_SEARCH_HANDS_FREE
2342             // with EXTRA_SECURE set to true if the device is securely locked
2343             PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
2344             boolean isLocked = mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
2345             if (!isLocked && pm.isScreenOn()) {
2346                 voiceIntent = new Intent(android.speech.RecognizerIntent.ACTION_WEB_SEARCH);
2347                 Log.i(TAG, "voice-based interactions: about to use ACTION_WEB_SEARCH");
2348             } else {
2349                 voiceIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
2350                 voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE,
2351                         isLocked && mKeyguardManager.isKeyguardSecure());
2352                 Log.i(TAG, "voice-based interactions: about to use ACTION_VOICE_SEARCH_HANDS_FREE");
2353             }
2354             // start the search activity
2355             if (needWakeLock) {
2356                 mMediaEventWakeLock.acquire();
2357             }
2358             try {
2359                 if (voiceIntent != null) {
2360                     voiceIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
2361                             | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
2362                     if (DEBUG) Log.d(TAG, "voiceIntent: " + voiceIntent);
2363                     mContext.startActivityAsUser(voiceIntent, UserHandle.CURRENT);
2364                 }
2365             } catch (ActivityNotFoundException e) {
2366                 Log.w(TAG, "No activity for search: " + e);
2367             } finally {
2368                 if (needWakeLock) {
2369                     mMediaEventWakeLock.release();
2370                 }
2371             }
2372         }
2373 
isVoiceKey(int keyCode)2374         private boolean isVoiceKey(int keyCode) {
2375             return keyCode == KeyEvent.KEYCODE_HEADSETHOOK
2376                     || (!mHasFeatureLeanback && keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
2377         }
2378 
isUserSetupComplete()2379         private boolean isUserSetupComplete() {
2380             return Settings.Secure.getIntForUser(mContext.getContentResolver(),
2381                     Settings.Secure.USER_SETUP_COMPLETE, 0, CURRENT.getIdentifier()) != 0;
2382         }
2383 
2384         // we only handle public stream types, which are 0-5
isValidLocalStreamType(int streamType)2385         private boolean isValidLocalStreamType(int streamType) {
2386             return streamType >= AudioManager.STREAM_VOICE_CALL
2387                     && streamType <= AudioManager.STREAM_NOTIFICATION;
2388         }
2389 
2390         private class MediaKeyListenerResultReceiver extends ResultReceiver implements Runnable {
2391             private final String mPackageName;
2392             private final int mPid;
2393             private final int mUid;
2394             private final boolean mAsSystemService;
2395             private final KeyEvent mKeyEvent;
2396             private final boolean mNeedWakeLock;
2397             private boolean mHandled;
2398 
MediaKeyListenerResultReceiver(String packageName, int pid, int uid, boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock)2399             private MediaKeyListenerResultReceiver(String packageName, int pid, int uid,
2400                     boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock) {
2401                 super(mHandler);
2402                 mHandler.postDelayed(this, MEDIA_KEY_LISTENER_TIMEOUT);
2403                 mPackageName = packageName;
2404                 mPid = pid;
2405                 mUid = uid;
2406                 mAsSystemService = asSystemService;
2407                 mKeyEvent = keyEvent;
2408                 mNeedWakeLock = needWakeLock;
2409             }
2410 
2411             @Override
run()2412             public void run() {
2413                 Log.d(TAG, "The media key listener is timed-out for " + mKeyEvent);
2414                 dispatchMediaKeyEvent();
2415             }
2416 
2417             @Override
onReceiveResult(int resultCode, Bundle resultData)2418             protected void onReceiveResult(int resultCode, Bundle resultData) {
2419                 if (resultCode == MediaSessionManager.RESULT_MEDIA_KEY_HANDLED) {
2420                     mHandled = true;
2421                     mHandler.removeCallbacks(this);
2422                     return;
2423                 }
2424                 dispatchMediaKeyEvent();
2425             }
2426 
dispatchMediaKeyEvent()2427             private void dispatchMediaKeyEvent() {
2428                 if (mHandled) {
2429                     return;
2430                 }
2431                 mHandled = true;
2432                 mHandler.removeCallbacks(this);
2433                 synchronized (mLock) {
2434                     if (isGlobalPriorityActiveLocked()) {
2435                         dispatchMediaKeyEventLocked(mPackageName, mPid, mUid, mAsSystemService,
2436                                 mKeyEvent, mNeedWakeLock);
2437                     } else {
2438                         mMediaKeyEventHandler.handleMediaKeyEventLocked(mPackageName, mPid, mUid,
2439                                 mAsSystemService, mKeyEvent, mNeedWakeLock);
2440                     }
2441                 }
2442             }
2443         }
2444 
2445         private KeyEventWakeLockReceiver mKeyEventReceiver = new KeyEventWakeLockReceiver(mHandler);
2446 
2447         class KeyEventWakeLockReceiver extends ResultReceiver implements Runnable,
2448                 PendingIntent.OnFinished {
2449             private final Handler mHandler;
2450             private int mRefCount = 0;
2451             private int mLastTimeoutId = 0;
2452 
KeyEventWakeLockReceiver(Handler handler)2453             KeyEventWakeLockReceiver(Handler handler) {
2454                 super(handler);
2455                 mHandler = handler;
2456             }
2457 
onTimeout()2458             public void onTimeout() {
2459                 synchronized (mLock) {
2460                     if (mRefCount == 0) {
2461                         // We've already released it, so just return
2462                         return;
2463                     }
2464                     mLastTimeoutId++;
2465                     mRefCount = 0;
2466                     releaseWakeLockLocked();
2467                 }
2468             }
2469 
acquireWakeLockLocked()2470             public void acquireWakeLockLocked() {
2471                 if (mRefCount == 0) {
2472                     mMediaEventWakeLock.acquire();
2473                 }
2474                 mRefCount++;
2475                 mHandler.removeCallbacks(this);
2476                 mHandler.postDelayed(this, WAKELOCK_TIMEOUT);
2477 
2478             }
2479 
2480             @Override
run()2481             public void run() {
2482                 onTimeout();
2483             }
2484 
2485             @Override
onReceiveResult(int resultCode, Bundle resultData)2486             protected void onReceiveResult(int resultCode, Bundle resultData) {
2487                 if (resultCode < mLastTimeoutId) {
2488                     // Ignore results from calls that were before the last
2489                     // timeout, just in case.
2490                     return;
2491                 } else {
2492                     synchronized (mLock) {
2493                         if (mRefCount > 0) {
2494                             mRefCount--;
2495                             if (mRefCount == 0) {
2496                                 releaseWakeLockLocked();
2497                             }
2498                         }
2499                     }
2500                 }
2501             }
2502 
releaseWakeLockLocked()2503             private void releaseWakeLockLocked() {
2504                 mMediaEventWakeLock.release();
2505                 mHandler.removeCallbacks(this);
2506             }
2507 
2508             @Override
onSendFinished(PendingIntent pendingIntent, Intent intent, int resultCode, String resultData, Bundle resultExtras)2509             public void onSendFinished(PendingIntent pendingIntent, Intent intent, int resultCode,
2510                     String resultData, Bundle resultExtras) {
2511                 onReceiveResult(resultCode, null);
2512             }
2513         };
2514 
2515         // A long press is determined by:
2516         // 1) A KeyEvent.ACTION_DOWN KeyEvent and repeat count of 0, followed by
2517         // 2) A KeyEvent.ACTION_DOWN KeyEvent with the same key code, a repeat count of 1, and
2518         //    FLAG_LONG_PRESS received within ViewConfiguration.getLongPressTimeout().
2519         // A tap is determined by:
2520         // 1) A KeyEvent.ACTION_DOWN KeyEvent followed by
2521         // 2) A KeyEvent.ACTION_UP KeyEvent with the same key code.
2522         class KeyEventHandler {
2523             private static final int KEY_TYPE_MEDIA = 0;
2524             private static final int KEY_TYPE_VOLUME = 1;
2525 
2526             private KeyEvent mTrackingFirstDownKeyEvent;
2527             private boolean mIsLongPressing;
2528             private Runnable mLongPressTimeoutRunnable;
2529             private int mMultiTapCount;
2530             private Runnable mMultiTapTimeoutRunnable;
2531             private int mMultiTapKeyCode;
2532             private int mKeyType;
2533 
KeyEventHandler(int keyType)2534             KeyEventHandler(int keyType) {
2535                 mKeyType = keyType;
2536             }
2537 
handleMediaKeyEventLocked(String packageName, int pid, int uid, boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock)2538             void handleMediaKeyEventLocked(String packageName, int pid, int uid,
2539                     boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock) {
2540                 handleKeyEventLocked(packageName, pid, uid, asSystemService, keyEvent, needWakeLock,
2541                         null, 0, false);
2542             }
2543 
handleVolumeKeyEventLocked(String packageName, int pid, int uid, boolean asSystemService, KeyEvent keyEvent, String opPackageName, int stream, boolean musicOnly)2544             void handleVolumeKeyEventLocked(String packageName, int pid, int uid,
2545                     boolean asSystemService, KeyEvent keyEvent, String opPackageName, int stream,
2546                     boolean musicOnly) {
2547                 handleKeyEventLocked(packageName, pid, uid, asSystemService, keyEvent, false,
2548                         opPackageName, stream, musicOnly);
2549             }
2550 
handleKeyEventLocked(String packageName, int pid, int uid, boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock, String opPackageName, int stream, boolean musicOnly)2551             void handleKeyEventLocked(String packageName, int pid, int uid,
2552                     boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock,
2553                     String opPackageName, int stream, boolean musicOnly) {
2554                 if (keyEvent.isCanceled()) {
2555                     return;
2556                 }
2557 
2558                 int overriddenKeyEvents = 0;
2559                 if (mCustomMediaKeyDispatcher != null
2560                         && mCustomMediaKeyDispatcher.getOverriddenKeyEvents() != null) {
2561                     overriddenKeyEvents = mCustomMediaKeyDispatcher.getOverriddenKeyEvents()
2562                             .get(keyEvent.getKeyCode());
2563                 }
2564                 cancelTrackingIfNeeded(packageName, pid, uid, asSystemService, keyEvent,
2565                         needWakeLock, opPackageName, stream, musicOnly, overriddenKeyEvents);
2566                 if (!needTracking(keyEvent, overriddenKeyEvents)) {
2567                     if (mKeyType == KEY_TYPE_VOLUME) {
2568                         dispatchVolumeKeyEventLocked(packageName, opPackageName, pid, uid,
2569                                 asSystemService, keyEvent, stream, musicOnly);
2570                     } else {
2571                         dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
2572                                 keyEvent, needWakeLock);
2573                     }
2574                     return;
2575                 }
2576 
2577                 if (isFirstDownKeyEvent(keyEvent)) {
2578                     mTrackingFirstDownKeyEvent = keyEvent;
2579                     mIsLongPressing = false;
2580                     return;
2581                 }
2582 
2583                 // Long press is always overridden here, otherwise the key event would have been
2584                 // already handled
2585                 if (isFirstLongPressKeyEvent(keyEvent)) {
2586                     mIsLongPressing = true;
2587                 }
2588                 if (mIsLongPressing) {
2589                     handleLongPressLocked(keyEvent, needWakeLock, overriddenKeyEvents);
2590                     return;
2591                 }
2592 
2593                 if (keyEvent.getAction() == KeyEvent.ACTION_UP) {
2594                     mTrackingFirstDownKeyEvent = null;
2595                     if (shouldTrackForMultipleTapsLocked(overriddenKeyEvents)) {
2596                         if (mMultiTapCount == 0) {
2597                             mMultiTapTimeoutRunnable = createSingleTapRunnable(packageName, pid,
2598                                     uid, asSystemService, keyEvent, needWakeLock,
2599                                     opPackageName, stream, musicOnly,
2600                                     isSingleTapOverridden(overriddenKeyEvents));
2601                             if (isSingleTapOverridden(overriddenKeyEvents)
2602                                     && !isDoubleTapOverridden(overriddenKeyEvents)
2603                                     && !isTripleTapOverridden(overriddenKeyEvents)) {
2604                                 mMultiTapTimeoutRunnable.run();
2605                             } else {
2606                                 mHandler.postDelayed(mMultiTapTimeoutRunnable,
2607                                         MULTI_TAP_TIMEOUT);
2608                                 mMultiTapCount = 1;
2609                                 mMultiTapKeyCode = keyEvent.getKeyCode();
2610                             }
2611                         } else if (mMultiTapCount == 1) {
2612                             mHandler.removeCallbacks(mMultiTapTimeoutRunnable);
2613                             mMultiTapTimeoutRunnable = createDoubleTapRunnable(packageName, pid,
2614                                     uid, asSystemService, keyEvent, needWakeLock, opPackageName,
2615                                     stream, musicOnly, isSingleTapOverridden(overriddenKeyEvents),
2616                                     isDoubleTapOverridden(overriddenKeyEvents));
2617                             if (isTripleTapOverridden(overriddenKeyEvents)) {
2618                                 mHandler.postDelayed(mMultiTapTimeoutRunnable, MULTI_TAP_TIMEOUT);
2619                                 mMultiTapCount = 2;
2620                             } else {
2621                                 mMultiTapTimeoutRunnable.run();
2622                             }
2623                         } else if (mMultiTapCount == 2) {
2624                             mHandler.removeCallbacks(mMultiTapTimeoutRunnable);
2625                             onTripleTap(keyEvent);
2626                         }
2627                     } else {
2628                         dispatchDownAndUpKeyEventsLocked(packageName, pid, uid, asSystemService,
2629                                 keyEvent, needWakeLock, opPackageName, stream, musicOnly);
2630                     }
2631                 }
2632             }
2633 
shouldTrackForMultipleTapsLocked(int overriddenKeyEvents)2634             private boolean shouldTrackForMultipleTapsLocked(int overriddenKeyEvents) {
2635                 return isSingleTapOverridden(overriddenKeyEvents)
2636                         || isDoubleTapOverridden(overriddenKeyEvents)
2637                         || isTripleTapOverridden(overriddenKeyEvents);
2638             }
2639 
cancelTrackingIfNeeded(String packageName, int pid, int uid, boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock, String opPackageName, int stream, boolean musicOnly, int overriddenKeyEvents)2640             private void cancelTrackingIfNeeded(String packageName, int pid, int uid,
2641                     boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock,
2642                     String opPackageName, int stream, boolean musicOnly, int overriddenKeyEvents) {
2643                 if (mTrackingFirstDownKeyEvent == null && mMultiTapTimeoutRunnable == null) {
2644                     return;
2645                 }
2646 
2647                 if (isFirstDownKeyEvent(keyEvent)) {
2648                     if (mLongPressTimeoutRunnable != null) {
2649                         mHandler.removeCallbacks(mLongPressTimeoutRunnable);
2650                         mLongPressTimeoutRunnable.run();
2651                     }
2652                     if (mMultiTapTimeoutRunnable != null
2653                             && keyEvent.getKeyCode() != mMultiTapKeyCode) {
2654                         runExistingMultiTapRunnableLocked();
2655                     }
2656                     resetLongPressTracking();
2657                     return;
2658                 }
2659 
2660                 if (mTrackingFirstDownKeyEvent != null
2661                         && mTrackingFirstDownKeyEvent.getDownTime() == keyEvent.getDownTime()
2662                         && mTrackingFirstDownKeyEvent.getKeyCode() == keyEvent.getKeyCode()
2663                         && keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
2664                     if (isFirstLongPressKeyEvent(keyEvent)) {
2665                         if (mMultiTapTimeoutRunnable != null) {
2666                             runExistingMultiTapRunnableLocked();
2667                         }
2668                         if ((overriddenKeyEvents & KEY_EVENT_LONG_PRESS) == 0) {
2669                             if (mKeyType == KEY_TYPE_VOLUME) {
2670                                 if (mCurrentFullUserRecord.mOnVolumeKeyLongPressListener == null) {
2671                                     dispatchVolumeKeyEventLocked(packageName, opPackageName, pid,
2672                                             uid, asSystemService, keyEvent, stream, musicOnly);
2673                                     mTrackingFirstDownKeyEvent = null;
2674                                 }
2675                             } else if (!isVoiceKey(keyEvent.getKeyCode())) {
2676                                 dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
2677                                         keyEvent, needWakeLock);
2678                                 mTrackingFirstDownKeyEvent = null;
2679                             }
2680                         }
2681                     } else if (keyEvent.getRepeatCount() > 1 && !mIsLongPressing) {
2682                         resetLongPressTracking();
2683                     }
2684                 }
2685             }
2686 
needTracking(KeyEvent keyEvent, int overriddenKeyEvents)2687             private boolean needTracking(KeyEvent keyEvent, int overriddenKeyEvents) {
2688                 if (!isFirstDownKeyEvent(keyEvent)) {
2689                     if (mTrackingFirstDownKeyEvent == null) {
2690                         return false;
2691                     } else if (mTrackingFirstDownKeyEvent.getDownTime() != keyEvent.getDownTime()
2692                             || mTrackingFirstDownKeyEvent.getKeyCode() != keyEvent.getKeyCode()) {
2693                         return false;
2694                     }
2695                 }
2696                 if (overriddenKeyEvents == 0) {
2697                     if (mKeyType == KEY_TYPE_VOLUME) {
2698                         if (mCurrentFullUserRecord.mOnVolumeKeyLongPressListener == null) {
2699                             return false;
2700                         }
2701                     } else if (!isVoiceKey(keyEvent.getKeyCode())) {
2702                         return false;
2703                     }
2704                 }
2705                 return true;
2706             }
2707 
runExistingMultiTapRunnableLocked()2708             private void runExistingMultiTapRunnableLocked() {
2709                 mHandler.removeCallbacks(mMultiTapTimeoutRunnable);
2710                 mMultiTapTimeoutRunnable.run();
2711             }
2712 
resetMultiTapTrackingLocked()2713             private void resetMultiTapTrackingLocked() {
2714                 mMultiTapCount = 0;
2715                 mMultiTapTimeoutRunnable = null;
2716                 mMultiTapKeyCode = 0;
2717             }
2718 
handleLongPressLocked(KeyEvent keyEvent, boolean needWakeLock, int overriddenKeyEvents)2719             private void handleLongPressLocked(KeyEvent keyEvent, boolean needWakeLock,
2720                     int overriddenKeyEvents) {
2721                 if (mCustomMediaKeyDispatcher != null
2722                         && isLongPressOverridden(overriddenKeyEvents)) {
2723                     mCustomMediaKeyDispatcher.onLongPress(keyEvent);
2724 
2725                     if (mLongPressTimeoutRunnable != null) {
2726                         mHandler.removeCallbacks(mLongPressTimeoutRunnable);
2727                     }
2728                     if (keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
2729                         if (mLongPressTimeoutRunnable == null) {
2730                             mLongPressTimeoutRunnable = createLongPressTimeoutRunnable(keyEvent);
2731                         }
2732                         mHandler.postDelayed(mLongPressTimeoutRunnable, LONG_PRESS_TIMEOUT);
2733                     } else {
2734                         resetLongPressTracking();
2735                     }
2736                 } else {
2737                     if (mKeyType == KEY_TYPE_VOLUME) {
2738                         if (isFirstLongPressKeyEvent(keyEvent)) {
2739                             dispatchVolumeKeyLongPressLocked(mTrackingFirstDownKeyEvent);
2740                         }
2741                         dispatchVolumeKeyLongPressLocked(keyEvent);
2742                     } else if (isFirstLongPressKeyEvent(keyEvent)
2743                             && isVoiceKey(keyEvent.getKeyCode())) {
2744                         // Default implementation
2745                         startVoiceInput(needWakeLock);
2746                         resetLongPressTracking();
2747                     }
2748                 }
2749             }
2750 
createLongPressTimeoutRunnable(KeyEvent keyEvent)2751             private Runnable createLongPressTimeoutRunnable(KeyEvent keyEvent) {
2752                 return new Runnable() {
2753                     @Override
2754                     public void run() {
2755                         if (mCustomMediaKeyDispatcher != null) {
2756                             mCustomMediaKeyDispatcher.onLongPress(createCanceledKeyEvent(keyEvent));
2757                         }
2758                         resetLongPressTracking();
2759                     }
2760                 };
2761             }
2762 
resetLongPressTracking()2763             private void resetLongPressTracking() {
2764                 mTrackingFirstDownKeyEvent = null;
2765                 mIsLongPressing = false;
2766                 mLongPressTimeoutRunnable = null;
2767             }
2768 
createCanceledKeyEvent(KeyEvent keyEvent)2769             private KeyEvent createCanceledKeyEvent(KeyEvent keyEvent) {
2770                 KeyEvent upEvent = KeyEvent.changeAction(keyEvent, KeyEvent.ACTION_UP);
2771                 return KeyEvent.changeTimeRepeat(upEvent, System.currentTimeMillis(), 0,
2772                         KeyEvent.FLAG_CANCELED);
2773             }
2774 
isFirstLongPressKeyEvent(KeyEvent keyEvent)2775             private boolean isFirstLongPressKeyEvent(KeyEvent keyEvent) {
2776                 return ((keyEvent.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0)
2777                         && keyEvent.getRepeatCount() == 1;
2778             }
2779 
isFirstDownKeyEvent(KeyEvent keyEvent)2780             private boolean isFirstDownKeyEvent(KeyEvent keyEvent) {
2781                 return keyEvent.getAction() == KeyEvent.ACTION_DOWN
2782                         && keyEvent.getRepeatCount() == 0;
2783             }
2784 
dispatchDownAndUpKeyEventsLocked(String packageName, int pid, int uid, boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock, String opPackageName, int stream, boolean musicOnly)2785             private void dispatchDownAndUpKeyEventsLocked(String packageName, int pid, int uid,
2786                     boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock,
2787                     String opPackageName, int stream, boolean musicOnly) {
2788                 KeyEvent downEvent = KeyEvent.changeAction(keyEvent, KeyEvent.ACTION_DOWN);
2789                 if (mKeyType == KEY_TYPE_VOLUME) {
2790                     dispatchVolumeKeyEventLocked(packageName, opPackageName, pid, uid,
2791                             asSystemService, downEvent, stream, musicOnly);
2792                     dispatchVolumeKeyEventLocked(packageName, opPackageName, pid, uid,
2793                             asSystemService, keyEvent, stream, musicOnly);
2794                 } else {
2795                     dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService, downEvent,
2796                             needWakeLock);
2797                     dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService, keyEvent,
2798                             needWakeLock);
2799                 }
2800             }
2801 
createSingleTapRunnable(String packageName, int pid, int uid, boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock, String opPackageName, int stream, boolean musicOnly, boolean overridden)2802             Runnable createSingleTapRunnable(String packageName, int pid, int uid,
2803                     boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock,
2804                     String opPackageName, int stream, boolean musicOnly, boolean overridden) {
2805                 return new Runnable() {
2806                     @Override
2807                     public void run() {
2808                         resetMultiTapTrackingLocked();
2809                         if (overridden) {
2810                             mCustomMediaKeyDispatcher.onSingleTap(keyEvent);
2811                         } else {
2812                             dispatchDownAndUpKeyEventsLocked(packageName, pid, uid, asSystemService,
2813                                     keyEvent, needWakeLock, opPackageName, stream, musicOnly);
2814                         }
2815                     }
2816                 };
2817             };
2818 
2819             Runnable createDoubleTapRunnable(String packageName, int pid, int uid,
2820                     boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock,
2821                     String opPackageName, int stream, boolean musicOnly,
2822                     boolean singleTapOverridden, boolean doubleTapOverridden) {
2823                 return new Runnable() {
2824                     @Override
2825                     public void run() {
2826                         resetMultiTapTrackingLocked();
2827                         if (doubleTapOverridden) {
2828                             mCustomMediaKeyDispatcher.onDoubleTap(keyEvent);
2829                         } else if (singleTapOverridden) {
2830                             mCustomMediaKeyDispatcher.onSingleTap(keyEvent);
2831                             mCustomMediaKeyDispatcher.onSingleTap(keyEvent);
2832                         } else {
2833                             dispatchDownAndUpKeyEventsLocked(packageName, pid, uid, asSystemService,
2834                                     keyEvent, needWakeLock, opPackageName, stream, musicOnly);
2835                             dispatchDownAndUpKeyEventsLocked(packageName, pid, uid, asSystemService,
2836                                     keyEvent, needWakeLock, opPackageName, stream, musicOnly);
2837                         }
2838                     }
2839                 };
2840             };
2841 
2842             private void onTripleTap(KeyEvent keyEvent) {
2843                 resetMultiTapTrackingLocked();
2844                 mCustomMediaKeyDispatcher.onTripleTap(keyEvent);
2845             }
2846         }
2847     }
2848 
2849     final class MessageHandler extends Handler {
2850         private static final int MSG_SESSIONS_1_CHANGED = 1;
2851         private static final int MSG_SESSIONS_2_CHANGED = 2;
2852         private final SparseArray<Integer> mIntegerCache = new SparseArray<>();
2853 
2854         @Override
2855         public void handleMessage(Message msg) {
2856             switch (msg.what) {
2857                 case MSG_SESSIONS_1_CHANGED:
2858                     pushSession1Changed((int) msg.obj);
2859                     break;
2860                 case MSG_SESSIONS_2_CHANGED:
2861                     pushSession2Changed((int) msg.obj);
2862                     break;
2863             }
2864         }
2865 
2866         public void postSessionsChanged(MediaSessionRecordImpl record) {
2867             // Use object instead of the arguments when posting message to remove pending requests.
2868             Integer userIdInteger = mIntegerCache.get(record.getUserId());
2869             if (userIdInteger == null) {
2870                 userIdInteger = Integer.valueOf(record.getUserId());
2871                 mIntegerCache.put(record.getUserId(), userIdInteger);
2872             }
2873 
2874             int msg = (record instanceof MediaSessionRecord)
2875                     ? MSG_SESSIONS_1_CHANGED : MSG_SESSIONS_2_CHANGED;
2876             removeMessages(msg, userIdInteger);
2877             obtainMessage(msg, userIdInteger).sendToTarget();
2878         }
2879     }
2880 }
2881