MediaSessionService.java revision 01fe661ae5da3739215d93922412df4b24c859a2
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 17package com.android.server.media; 18 19import android.content.Context; 20import android.media.IMediaSession; 21import android.media.IMediaSessionCallback; 22import android.media.IMediaSessionManager; 23import android.os.Binder; 24import android.os.RemoteException; 25import android.text.TextUtils; 26import android.util.Log; 27 28import com.android.server.SystemService; 29 30import java.util.ArrayList; 31 32/** 33 * System implementation of MediaSessionManager 34 */ 35public class MediaSessionService extends SystemService { 36 private static final String TAG = "MediaSessionService"; 37 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 38 39 private final SessionManagerImpl mSessionManagerImpl; 40 41 private final ArrayList<MediaSessionRecord> mSessions 42 = new ArrayList<MediaSessionRecord>(); 43 private final Object mLock = new Object(); 44 45 public MediaSessionService(Context context) { 46 super(context); 47 mSessionManagerImpl = new SessionManagerImpl(); 48 } 49 50 @Override 51 public void onStart() { 52 publishBinderService(Context.MEDIA_SESSION_SERVICE, mSessionManagerImpl); 53 } 54 55 void sessionDied(MediaSessionRecord session) { 56 synchronized (mSessions) { 57 destroySessionLocked(session); 58 } 59 } 60 61 void destroySession(MediaSessionRecord session) { 62 synchronized (mSessions) { 63 destroySessionLocked(session); 64 } 65 } 66 67 private void destroySessionLocked(MediaSessionRecord session) { 68 mSessions.remove(session); 69 } 70 71 private void enforcePackageName(String packageName, int uid) { 72 if (TextUtils.isEmpty(packageName)) { 73 throw new IllegalArgumentException("packageName may not be empty"); 74 } 75 String[] packages = getContext().getPackageManager().getPackagesForUid(uid); 76 final int packageCount = packages.length; 77 for (int i = 0; i < packageCount; i++) { 78 if (packageName.equals(packages[i])) { 79 return; 80 } 81 } 82 throw new IllegalArgumentException("packageName is not owned by the calling process"); 83 } 84 85 private MediaSessionRecord createSessionInternal(int pid, String packageName, 86 IMediaSessionCallback cb, String tag) { 87 synchronized (mLock) { 88 return createSessionLocked(pid, packageName, cb, tag); 89 } 90 } 91 92 private MediaSessionRecord createSessionLocked(int pid, String packageName, 93 IMediaSessionCallback cb, String tag) { 94 final MediaSessionRecord session = new MediaSessionRecord(pid, packageName, cb, tag, this); 95 try { 96 cb.asBinder().linkToDeath(session, 0); 97 } catch (RemoteException e) { 98 throw new RuntimeException("Media Session owner died prematurely.", e); 99 } 100 synchronized (mSessions) { 101 mSessions.add(session); 102 } 103 if (DEBUG) { 104 Log.d(TAG, "Created session for package " + packageName + " with tag " + tag); 105 } 106 return session; 107 } 108 109 class SessionManagerImpl extends IMediaSessionManager.Stub { 110 @Override 111 public IMediaSession createSession(String packageName, IMediaSessionCallback cb, String tag) 112 throws RemoteException { 113 final int pid = Binder.getCallingPid(); 114 final int uid = Binder.getCallingUid(); 115 final long token = Binder.clearCallingIdentity(); 116 try { 117 enforcePackageName(packageName, uid); 118 if (cb == null) { 119 throw new IllegalArgumentException("Controller callback cannot be null"); 120 } 121 return createSessionInternal(pid, packageName, cb, tag).getSessionBinder(); 122 } finally { 123 Binder.restoreCallingIdentity(token); 124 } 125 } 126 } 127 128} 129