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