前言

跟一下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

之前文章《SystemServer的启动之一》介绍过这里会启动三种类服务:

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如何启动服务,之前也介绍过的,也是在《SystemServer的启动之一》。

SystemServiceManager.java

下面之时简单总结一下startService()的启动:

  1. 判断serviceClass是否继承SystemService

  2. 获取构造函数初始化Service对象

  3. 调用真正启动服务的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
  1. 创建MediaSessionService对象

  2. 调用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的启动已经完成,其他的暂不跟。

  1. 《Android源码》

相关文章

暂无评论

none
暂无评论...