FileDocCategorySizeDatePackage
MediaRouterService.javaAPI DocAndroid 5.1 API58124Thu Mar 12 22:22:42 GMT 2015com.android.server.media

MediaRouterService

public final class MediaRouterService extends IMediaRouterService.Stub implements Watchdog.Monitor
Provides a mechanism for discovering media routes and manages media playback behalf of applications.

Currently supports discovering remote displays via remote display provider services that have been registered by applications.

Fields Summary
private static final String
TAG
private static final boolean
DEBUG
static final long
CONNECTING_TIMEOUT
Timeout in milliseconds for a selected route to transition from a disconnected state to a connecting state. If we don't observe any progress within this interval, then we will give up and unselect the route.
static final long
CONNECTED_TIMEOUT
Timeout in milliseconds for a selected route to transition from a connecting state to a connected state. If we don't observe any progress within this interval, then we will give up and unselect the route.
private final android.content.Context
mContext
private final Object
mLock
private final android.util.SparseArray
mUserRecords
private final android.util.ArrayMap
mAllClientRecords
private int
mCurrentUserId
Constructors Summary
public MediaRouterService(android.content.Context context)


       
        mContext = context;
        Watchdog.getInstance().addMonitor(this);
    
Methods Summary
voidclientDied(com.android.server.media.MediaRouterService$ClientRecord clientRecord)

        synchronized (mLock) {
            unregisterClientLocked(clientRecord.mClient, true);
        }
    
private voiddisposeClientLocked(com.android.server.media.MediaRouterService$ClientRecord clientRecord, boolean died)

        if (DEBUG) {
            if (died) {
                Slog.d(TAG, clientRecord + ": Died!");
            } else {
                Slog.d(TAG, clientRecord + ": Unregistered");
            }
        }
        if (clientRecord.mRouteTypes != 0 || clientRecord.mActiveScan) {
            clientRecord.mUserRecord.mHandler.sendEmptyMessage(
                    UserHandler.MSG_UPDATE_DISCOVERY_REQUEST);
        }
        clientRecord.dispose();
    
private voiddisposeUserIfNeededLocked(com.android.server.media.MediaRouterService$UserRecord userRecord)

        // If there are no records left and the user is no longer current then go ahead
        // and purge the user record and all of its associated state.  If the user is current
        // then leave it alone since we might be connected to a route or want to query
        // the same route information again soon.
        if (userRecord.mUserId != mCurrentUserId
                && userRecord.mClientRecords.isEmpty()) {
            if (DEBUG) {
                Slog.d(TAG, userRecord + ": Disposed");
            }
            mUserRecords.remove(userRecord.mUserId);
            // Note: User already stopped (by switchUser) so no need to send stop message here.
        }
    
public voiddump(java.io.FileDescriptor fd, java.io.PrintWriter pw, java.lang.String[] args)

        if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
                != PackageManager.PERMISSION_GRANTED) {
            pw.println("Permission Denial: can't dump MediaRouterService from from pid="
                    + Binder.getCallingPid()
                    + ", uid=" + Binder.getCallingUid());
            return;
        }

        pw.println("MEDIA ROUTER SERVICE (dumpsys media_router)");
        pw.println();
        pw.println("Global state");
        pw.println("  mCurrentUserId=" + mCurrentUserId);

        synchronized (mLock) {
            final int count = mUserRecords.size();
            for (int i = 0; i < count; i++) {
                UserRecord userRecord = mUserRecords.valueAt(i);
                pw.println();
                userRecord.dump(pw, "");
            }
        }
    
public android.media.MediaRouterClientStategetState(android.media.IMediaRouterClient client)

        if (client == null) {
            throw new IllegalArgumentException("client must not be null");
        }

        final long token = Binder.clearCallingIdentity();
        try {
            synchronized (mLock) {
                return getStateLocked(client);
            }
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    
private android.media.MediaRouterClientStategetStateLocked(android.media.IMediaRouterClient client)

        ClientRecord clientRecord = mAllClientRecords.get(client.asBinder());
        if (clientRecord != null) {
            return clientRecord.getState();
        }
        return null;
    
private voidinitializeClientLocked(com.android.server.media.MediaRouterService$ClientRecord clientRecord)

        if (DEBUG) {
            Slog.d(TAG, clientRecord + ": Registered");
        }
    
private voidinitializeUserLocked(com.android.server.media.MediaRouterService$UserRecord userRecord)

        if (DEBUG) {
            Slog.d(TAG, userRecord + ": Initialized");
        }
        if (userRecord.mUserId == mCurrentUserId) {
            userRecord.mHandler.sendEmptyMessage(UserHandler.MSG_START);
        }
    
public voidmonitor()

        synchronized (mLock) { /* check for deadlock */ }
    
public voidregisterClientAsUser(android.media.IMediaRouterClient client, java.lang.String packageName, int userId)

        if (client == null) {
            throw new IllegalArgumentException("client must not be null");
        }

        final int uid = Binder.getCallingUid();
        if (!validatePackageName(uid, packageName)) {
            throw new SecurityException("packageName must match the calling uid");
        }

        final int pid = Binder.getCallingPid();
        final int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
                false /*allowAll*/, true /*requireFull*/, "registerClientAsUser", packageName);
        final boolean trusted = mContext.checkCallingOrSelfPermission(
                android.Manifest.permission.CONFIGURE_WIFI_DISPLAY) ==
                PackageManager.PERMISSION_GRANTED;
        final long token = Binder.clearCallingIdentity();
        try {
            synchronized (mLock) {
                registerClientLocked(client, pid, packageName, resolvedUserId, trusted);
            }
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    
private voidregisterClientLocked(android.media.IMediaRouterClient client, int pid, java.lang.String packageName, int userId, boolean trusted)

        final IBinder binder = client.asBinder();
        ClientRecord clientRecord = mAllClientRecords.get(binder);
        if (clientRecord == null) {
            boolean newUser = false;
            UserRecord userRecord = mUserRecords.get(userId);
            if (userRecord == null) {
                userRecord = new UserRecord(userId);
                newUser = true;
            }
            clientRecord = new ClientRecord(userRecord, client, pid, packageName, trusted);
            try {
                binder.linkToDeath(clientRecord, 0);
            } catch (RemoteException ex) {
                throw new RuntimeException("Media router client died prematurely.", ex);
            }

            if (newUser) {
                mUserRecords.put(userId, userRecord);
                initializeUserLocked(userRecord);
            }

            userRecord.mClientRecords.add(clientRecord);
            mAllClientRecords.put(binder, clientRecord);
            initializeClientLocked(clientRecord);
        }
    
public voidrequestSetVolume(android.media.IMediaRouterClient client, java.lang.String routeId, int volume)

        if (client == null) {
            throw new IllegalArgumentException("client must not be null");
        }
        if (routeId == null) {
            throw new IllegalArgumentException("routeId must not be null");
        }

        final long token = Binder.clearCallingIdentity();
        try {
            synchronized (mLock) {
                requestSetVolumeLocked(client, routeId, volume);
            }
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    
private voidrequestSetVolumeLocked(android.media.IMediaRouterClient client, java.lang.String routeId, int volume)

        final IBinder binder = client.asBinder();
        ClientRecord clientRecord = mAllClientRecords.get(binder);
        if (clientRecord != null) {
            clientRecord.mUserRecord.mHandler.obtainMessage(
                    UserHandler.MSG_REQUEST_SET_VOLUME, volume, 0, routeId).sendToTarget();
        }
    
public voidrequestUpdateVolume(android.media.IMediaRouterClient client, java.lang.String routeId, int direction)

        if (client == null) {
            throw new IllegalArgumentException("client must not be null");
        }
        if (routeId == null) {
            throw new IllegalArgumentException("routeId must not be null");
        }

        final long token = Binder.clearCallingIdentity();
        try {
            synchronized (mLock) {
                requestUpdateVolumeLocked(client, routeId, direction);
            }
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    
private voidrequestUpdateVolumeLocked(android.media.IMediaRouterClient client, java.lang.String routeId, int direction)

        final IBinder binder = client.asBinder();
        ClientRecord clientRecord = mAllClientRecords.get(binder);
        if (clientRecord != null) {
            clientRecord.mUserRecord.mHandler.obtainMessage(
                    UserHandler.MSG_REQUEST_UPDATE_VOLUME, direction, 0, routeId).sendToTarget();
        }
    
public voidsetDiscoveryRequest(android.media.IMediaRouterClient client, int routeTypes, boolean activeScan)

        if (client == null) {
            throw new IllegalArgumentException("client must not be null");
        }

        final long token = Binder.clearCallingIdentity();
        try {
            synchronized (mLock) {
                setDiscoveryRequestLocked(client, routeTypes, activeScan);
            }
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    
private voidsetDiscoveryRequestLocked(android.media.IMediaRouterClient client, int routeTypes, boolean activeScan)

        final IBinder binder = client.asBinder();
        ClientRecord clientRecord = mAllClientRecords.get(binder);
        if (clientRecord != null) {
            // Only let the system discover remote display routes for now.
            if (!clientRecord.mTrusted) {
                routeTypes &= ~MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY;
            }

            if (clientRecord.mRouteTypes != routeTypes
                    || clientRecord.mActiveScan != activeScan) {
                if (DEBUG) {
                    Slog.d(TAG, clientRecord + ": Set discovery request, routeTypes=0x"
                            + Integer.toHexString(routeTypes) + ", activeScan=" + activeScan);
                }
                clientRecord.mRouteTypes = routeTypes;
                clientRecord.mActiveScan = activeScan;
                clientRecord.mUserRecord.mHandler.sendEmptyMessage(
                        UserHandler.MSG_UPDATE_DISCOVERY_REQUEST);
            }
        }
    
public voidsetSelectedRoute(android.media.IMediaRouterClient client, java.lang.String routeId, boolean explicit)

        if (client == null) {
            throw new IllegalArgumentException("client must not be null");
        }

        final long token = Binder.clearCallingIdentity();
        try {
            synchronized (mLock) {
                setSelectedRouteLocked(client, routeId, explicit);
            }
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    
private voidsetSelectedRouteLocked(android.media.IMediaRouterClient client, java.lang.String routeId, boolean explicit)

        ClientRecord clientRecord = mAllClientRecords.get(client.asBinder());
        if (clientRecord != null) {
            final String oldRouteId = clientRecord.mSelectedRouteId;
            if (!Objects.equals(routeId, oldRouteId)) {
                if (DEBUG) {
                    Slog.d(TAG, clientRecord + ": Set selected route, routeId=" + routeId
                            + ", oldRouteId=" + oldRouteId
                            + ", explicit=" + explicit);
                }

                clientRecord.mSelectedRouteId = routeId;
                if (explicit) {
                    // Any app can disconnect from the globally selected route.
                    if (oldRouteId != null) {
                        clientRecord.mUserRecord.mHandler.obtainMessage(
                                UserHandler.MSG_UNSELECT_ROUTE, oldRouteId).sendToTarget();
                    }
                    // Only let the system connect to new global routes for now.
                    // A similar check exists in the display manager for wifi display.
                    if (routeId != null && clientRecord.mTrusted) {
                        clientRecord.mUserRecord.mHandler.obtainMessage(
                                UserHandler.MSG_SELECT_ROUTE, routeId).sendToTarget();
                    }
                }
            }
        }
    
voidswitchUser()

        synchronized (mLock) {
            int userId = ActivityManager.getCurrentUser();
            if (mCurrentUserId != userId) {
                final int oldUserId = mCurrentUserId;
                mCurrentUserId = userId; // do this first

                UserRecord oldUser = mUserRecords.get(oldUserId);
                if (oldUser != null) {
                    oldUser.mHandler.sendEmptyMessage(UserHandler.MSG_STOP);
                    disposeUserIfNeededLocked(oldUser); // since no longer current user
                }

                UserRecord newUser = mUserRecords.get(userId);
                if (newUser != null) {
                    newUser.mHandler.sendEmptyMessage(UserHandler.MSG_START);
                }
            }
        }
    
public voidsystemRunning()

        IntentFilter filter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
        mContext.registerReceiver(new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if (intent.getAction().equals(Intent.ACTION_USER_SWITCHED)) {
                    switchUser();
                }
            }
        }, filter);

        switchUser();
    
public voidunregisterClient(android.media.IMediaRouterClient client)

        if (client == null) {
            throw new IllegalArgumentException("client must not be null");
        }

        final long token = Binder.clearCallingIdentity();
        try {
            synchronized (mLock) {
                unregisterClientLocked(client, false);
            }
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    
private voidunregisterClientLocked(android.media.IMediaRouterClient client, boolean died)

        ClientRecord clientRecord = mAllClientRecords.remove(client.asBinder());
        if (clientRecord != null) {
            UserRecord userRecord = clientRecord.mUserRecord;
            userRecord.mClientRecords.remove(clientRecord);
            disposeClientLocked(clientRecord, died);
            disposeUserIfNeededLocked(userRecord); // since client removed from user
        }
    
private booleanvalidatePackageName(int uid, java.lang.String packageName)

        if (packageName != null) {
            String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid);
            if (packageNames != null) {
                for (String n : packageNames) {
                    if (n.equals(packageName)) {
                        return true;
                    }
                }
            }
        }
        return false;