目录
前言
跟一下Android多媒体中比较重要的一个服务类:MediaSessionService。这个主要涉及媒体按键的监听等,记录一下,方便自己查阅。
涉及目录:
frameworks\base\services\java\com\android\server\SystemServer.java frameworks\base\services\core\java\com\android\server\SystemServiceManager.java frameworks\base\services\core\java\com\android\server\media\MediaSessionService.java
正文
系统服务的启动离不开SystemServer,都是在这里启动的。
SystemServer.java
之前文章《》介绍过这里会启动三种类服务:
1. 引导服务 startBootstrapServices() 2. 核心服务 startCoreServices() 3. 其他服务 startOtherServices()
我们今天的主角MediaSessionService也是在startOtherServices()启动的。
private static final String MEDIA_SESSION_SERVICE_CLASS = "com.android.server.media.MediaSessionService";
private void startOtherServices(@NonNull TimingsTraceAndSlog t) { //略 mSystemServiceManager.startService(MEDIA_SESSION_SERVICE_CLASS); //略 }
关于SystemServiceManager如何启动服务,之前也介绍过的,也是在《》。
SystemServiceManager.java
下面之时简单总结一下startService()的启动:
判断serviceClass是否继承SystemService
获取构造函数初始化Service对象
调用真正启动服务的startService()
startService()
public void startService(@NonNull final SystemService service) { //添加到服务列表,后面可以通过getService获取服务。 mServices.add(service); try { //调用服务中的onStart() service.onStart(); } catch (RuntimeException ex) { throw new RuntimeException("Failed to start service " + service.getClass().getName() + ": onStart threw an exception", ex); } }
启动的服务前提条件继承SystemService,然后创建构造函数进行初始化[这里用了反射],最后调用start()方法。
MediaSessionService.java
创建MediaSessionService对象
调用MediaSessionService.start()
MediaSessionService()
public MediaSessionService(Context context) { super(context); mContext = context; //SessionManagerImpl看命名,就是SessionManager的实现类 mSessionManagerImpl = new SessionManagerImpl(); PowerManager pm = mContext.getSystemService(PowerManager.class); mMediaEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleMediaEvent"); mNotificationManager = mContext.getSystemService(NotificationManager.class); mAudioManager = mContext.getSystemService(AudioManager.class); }
构造函数中重点mSessionManagerImpl的初始化,后面MediaSession通信需要。
SessionManagerImpl继承ISessionManager.Stub,对应AIDL熟悉的就知道这个。这里提一下createSession(),用于创建Binder通信的。
class SessionManagerImpl extends ISessionManager.Stub { //略 @Override public ISession createSession(String packageName, ISessionCallback cb, String tag, Bundle sessionInfo, int userId) throws RemoteException { final int pid = Binder.getCallingPid(); final int uid = Binder.getCallingUid(); final long token = Binder.clearCallingIdentity(); try { enforcePackageName(packageName, uid); int resolvedUserId = handleIncomingUser(pid, uid, userId, packageName); if (cb == null) { throw new IllegalArgumentException("Controller callback cannot be null"); } //MediaSessionRecordImpl MediaSessionRecord session = createSessionInternal( pid, uid, resolvedUserId, packageName, cb, tag, sessionInfo); if (session == null) { throw new IllegalStateException("Failed to create a new session record"); } ISession sessionBinder = session.getSessionBinder(); if (sessionBinder == null) { throw new IllegalStateException("Invalid session record"); } return sessionBinder; } catch (Exception e) { throw e; } finally { Binder.restoreCallingIdentity(token); } } //略 }
onStart()
@Override public void onStart() { //添加到服务列表(ServiceManager.addService()) publishBinderService(Context.MEDIA_SESSION_SERVICE, mSessionManagerImpl); //略 //监听器初始化 mAudioPlayerStateMonitor = AudioPlayerStateMonitor.getInstance(mContext); //注册监听,【重要】 mAudioPlayerStateMonitor.registerListener( (config, isRemoved) -> { //这个回调AudioPlayerState,状态变了,会通知去更新MediaButtonSession队列 if (config.getPlayerType() == AudioPlaybackConfiguration.PLAYER_TYPE_JAM_SOUNDPOOL) { return; } synchronized (mLock) { FullUserRecord user = getFullUserRecordLocked( UserHandle.getUserHandleForUid(config.getClientUid()) .getIdentifier()); //不为null时通知updateMediaButtonSessionIfNeeded刷新。 if (user != null) { //mPriorityStack为MediaSessionStack对象。 user.mPriorityStack.updateMediaButtonSessionIfNeeded(); } } }, null /* handler */); //略 }
mPriorityStack是MediaSessionStack对象,在FullUserRecord()中初始化的。
FullUserRecord的创建是在updateUser()
private void updateUser() { synchronized (mLock) { UserManager manager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); mFullUserIds.clear(); List<UserHandle> allUsers = manager.getUserHandles(/*excludeDying=*/false); if (allUsers != null) { for (UserHandle user : allUsers) { UserHandle parent = manager.getProfileParent(user); if (parent != null) { mFullUserIds.put(user.getIdentifier(), parent.getIdentifier()); } else { mFullUserIds.put(user.getIdentifier(), user.getIdentifier()); if (mUserRecords.get(user.getIdentifier()) == null) { //创建FullUserRecord对象 mUserRecords.put(user.getIdentifier(), new FullUserRecord(user.getIdentifier())); } } } } //略 } }
FullUserRecord是实现MediaSessionStack.OnMediaButtonSessionChangedListener接口的。
final class FullUserRecord implements MediaSessionStack.OnMediaButtonSessionChangedListener { //略 FullUserRecord(int fullUserId) { mFullUserId = fullUserId; mContentResolver = mContext.createContextAsUser(UserHandle.of(mFullUserId), 0) .getContentResolver(); //重点 mPriorityStack就是MediaSessionStack对象 mPriorityStack = new MediaSessionStack(mAudioPlayerStateMonitor, this); String mediaButtonReceiverInfo = Settings.Secure.getString(mContentResolver, MEDIA_BUTTON_RECEIVER); mLastMediaButtonReceiverHolder = MediaButtonReceiverHolder.unflattenFromString( mContext, mediaButtonReceiverInfo); } //略 }
根据上面
user.mPriorityStack.updateMediaButtonSessionIfNeeded();
其实就是
MediaSessionStack.updateMediaButtonSessionIfNeeded();
MediaSessionService的启动已经完成,其他的暂不跟。