Loading media/java/android/media/session/MediaSession.java +4 −0 Original line number Diff line number Diff line Loading @@ -266,8 +266,12 @@ public final class MediaSession { * playback after the session has been stopped. If your app is started in * this way an {@link Intent#ACTION_MEDIA_BUTTON} intent will be sent via * the pending intent. * <p> * The pending intent is recommended to be explicit to follow the security recommendation of * {@link PendingIntent#getActivity}. * * @param mbr The {@link PendingIntent} to send the media button event to. * @see PendingIntent#getActivity */ public void setMediaButtonReceiver(@Nullable PendingIntent mbr) { try { Loading services/core/java/com/android/server/media/MediaButtonReceiverHolder.java 0 → 100644 +360 −0 Original line number Diff line number Diff line /* * Copyright 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.media; import android.annotation.IntDef; import android.annotation.NonNull; import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ComponentInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.os.Handler; import android.os.UserHandle; import android.text.TextUtils; import android.util.Log; import android.view.KeyEvent; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.List; /** * Holds the media button receiver, and also provides helper methods around it. */ final class MediaButtonReceiverHolder { public static final int COMPONENT_TYPE_INVALID = 0; public static final int COMPONENT_TYPE_BROADCAST = 1; public static final int COMPONENT_TYPE_ACTIVITY = 2; public static final int COMPONENT_TYPE_SERVICE = 3; @IntDef(value = { COMPONENT_TYPE_INVALID, COMPONENT_TYPE_BROADCAST, COMPONENT_TYPE_ACTIVITY, COMPONENT_TYPE_SERVICE, }) @Retention(RetentionPolicy.SOURCE) public @interface ComponentType {} private static final String TAG = "PendingIntentHolder"; private static final boolean DEBUG_KEY_EVENT = MediaSessionService.DEBUG_KEY_EVENT; private static final String COMPONENT_NAME_USER_ID_DELIM = ","; private final int mUserId; private final PendingIntent mPendingIntent; private final ComponentName mComponentName; private final String mPackageName; @ComponentType private final int mComponentType; /** * Unflatten from string which is previously flattened string via flattenToString(). * <p> * It's used to store and restore media button receiver across the boot, by keeping the intent's * component name to the persistent storage. * * @param mediaButtonReceiverInfo previously flattened string via flattenToString() * @return new instance if the string was valid. {@code null} otherwise. */ public static MediaButtonReceiverHolder unflattenFromString( Context context, String mediaButtonReceiverInfo) { if (TextUtils.isEmpty(mediaButtonReceiverInfo)) { return null; } String[] tokens = mediaButtonReceiverInfo.split(COMPONENT_NAME_USER_ID_DELIM); if (tokens == null || (tokens.length != 2 && tokens.length != 3)) { return null; } ComponentName componentName = ComponentName.unflattenFromString(tokens[0]); int userId = Integer.parseInt(tokens[1]); // Guess component type if the OS version is updated from the older version. int componentType = (tokens.length == 3) ? Integer.parseInt(tokens[2]) : getComponentType(context, componentName); return new MediaButtonReceiverHolder(userId, null, componentName, componentType); } /** * Creates a new instance. * * @param context context * @param userId userId * @param pendingIntent pending intent * @return Can be {@code null} if pending intent was null. */ public static MediaButtonReceiverHolder create(Context context, int userId, PendingIntent pendingIntent) { if (pendingIntent == null) { return null; } ComponentName componentName = (pendingIntent != null && pendingIntent.getIntent() != null) ? pendingIntent.getIntent().getComponent() : null; if (componentName != null) { // Explicit intent, where component name is in the PendingIntent. return new MediaButtonReceiverHolder(userId, pendingIntent, componentName, getComponentType(context, componentName)); } // Implicit intent, where component name isn't in the PendingIntent. Try resolve. PackageManager pm = context.getPackageManager(); Intent intent = pendingIntent.getIntent(); if ((componentName = resolveImplicitServiceIntent(pm, intent)) != null) { return new MediaButtonReceiverHolder( userId, pendingIntent, componentName, COMPONENT_TYPE_SERVICE); } else if ((componentName = resolveManifestDeclaredBroadcastReceiverIntent(pm, intent)) != null) { return new MediaButtonReceiverHolder( userId, pendingIntent, componentName, COMPONENT_TYPE_BROADCAST); } else if ((componentName = resolveImplicitActivityIntent(pm, intent)) != null) { return new MediaButtonReceiverHolder( userId, pendingIntent, componentName, COMPONENT_TYPE_ACTIVITY); } // Failed to resolve target component for the pending intent. It's unlikely to be usable. // However, the pending intent would be still used, just to follow the legacy behavior. Log.w(TAG, "Unresolvable implicit intent is set, pi=" + pendingIntent); String packageName = (pendingIntent != null && pendingIntent.getIntent() != null) ? pendingIntent.getIntent().getPackage() : null; return new MediaButtonReceiverHolder(userId, pendingIntent, packageName != null ? packageName : ""); } private MediaButtonReceiverHolder(int userId, PendingIntent pendingIntent, ComponentName componentName, @ComponentType int componentType) { mUserId = userId; mPendingIntent = pendingIntent; mComponentName = componentName; mPackageName = componentName.getPackageName(); mComponentType = componentType; } private MediaButtonReceiverHolder(int userId, PendingIntent pendingIntent, String packageName) { mUserId = userId; mPendingIntent = pendingIntent; mComponentName = null; mPackageName = packageName; mComponentType = COMPONENT_TYPE_INVALID; } /** * @return the user id */ public int getUserId() { return mUserId; } /** * @return package name that the media button receiver would be sent to. */ @NonNull public String getPackageName() { return mPackageName; } /** * Sends the media key event to the media button receiver. * <p> * This prioritizes using use pending intent for sending media key event. * * @param context context to be used to call PendingIntent#send * @param keyEvent keyEvent to send * @param resultCode result code to be used to call PendingIntent#send * Ignored if there's no valid pending intent. * @param onFinishedListener callback to be used to get result of PendingIntent#send. * Ignored if there's no valid pending intent. * @param handler handler to be used to call onFinishedListener * Ignored if there's no valid pending intent. * @see PendingIntent#send(Context, int, Intent, PendingIntent.OnFinished, Handler) */ public boolean send(Context context, KeyEvent keyEvent, String callingPackageName, int resultCode, PendingIntent.OnFinished onFinishedListener, Handler handler) { Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); mediaButtonIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent); // TODO: Find a way to also send PID/UID in secure way. mediaButtonIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, callingPackageName); if (mPendingIntent != null) { if (DEBUG_KEY_EVENT) { Log.d(TAG, "Sending " + keyEvent + " to the last known PendingIntent " + mPendingIntent); } try { mPendingIntent.send( context, resultCode, mediaButtonIntent, onFinishedListener, handler); } catch (PendingIntent.CanceledException e) { Log.w(TAG, "Error sending key event to media button receiver " + mPendingIntent, e); return false; } } else if (mComponentName != null) { if (DEBUG_KEY_EVENT) { Log.d(TAG, "Sending " + keyEvent + " to the restored intent " + mComponentName + ", type=" + mComponentType); } mediaButtonIntent.setComponent(mComponentName); UserHandle userHandle = UserHandle.of(mUserId); try { switch (mComponentType) { case COMPONENT_TYPE_ACTIVITY: context.startActivityAsUser(mediaButtonIntent, userHandle); break; case COMPONENT_TYPE_SERVICE: context.startForegroundServiceAsUser(mediaButtonIntent, userHandle); break; default: // Legacy behavior for other cases. context.sendBroadcastAsUser(mediaButtonIntent, userHandle); } } catch (Exception e) { Log.w(TAG, "Error sending media button to the restored intent " + mComponentName + ", type=" + mComponentType, e); return false; } } else { // Leave log, just in case. Log.e(TAG, "Shouldn't be happen -- pending intent or component name must be set"); return false; } return true; } @Override public String toString() { if (mPendingIntent != null) { return "MBR {pi=" + mPendingIntent + ", type=" + mComponentType + "}"; } return "Restored MBR {component=" + mComponentName + ", type=" + mComponentType + "}"; } /** * @return flattened string. Can be empty string if the MBR is created with implicit intent. */ public String flattenToString() { if (mComponentName == null) { // We don't know which component would receive the key event. return ""; } return String.join(COMPONENT_NAME_USER_ID_DELIM, mComponentName.toString(), String.valueOf(mUserId), String.valueOf(mComponentType)); } /** * Gets the type of the component * * @param context context * @param componentName component name * @return A component type */ @ComponentType private static int getComponentType(Context context, ComponentName componentName) { if (componentName == null) { return COMPONENT_TYPE_INVALID; } PackageManager pm = context.getPackageManager(); try { ActivityInfo activityInfo = pm.getActivityInfo(componentName, PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE | PackageManager.GET_ACTIVITIES); if (activityInfo != null) { return COMPONENT_TYPE_ACTIVITY; } } catch (PackageManager.NameNotFoundException e) { } try { ServiceInfo serviceInfo = pm.getServiceInfo(componentName, PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE | PackageManager.GET_SERVICES); if (serviceInfo != null) { return COMPONENT_TYPE_SERVICE; } } catch (PackageManager.NameNotFoundException e) { } // Pick legacy behavior for BroadcastReceiver or unknown. return COMPONENT_TYPE_BROADCAST; } private static ComponentName resolveImplicitServiceIntent(PackageManager pm, Intent intent) { // Flag explanations. // - MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE: // filter apps regardless of the phone's locked/unlocked state. // - GET_SERVICES: Return service return createComponentName(pm.resolveService(intent, PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE | PackageManager.GET_SERVICES)); } private static ComponentName resolveManifestDeclaredBroadcastReceiverIntent( PackageManager pm, Intent intent) { // Flag explanations. // - MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE: // filter apps regardless of the phone's locked/unlocked state. List<ResolveInfo> resolveInfos = pm.queryBroadcastReceivers(intent, PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE); return (resolveInfos != null && !resolveInfos.isEmpty()) ? createComponentName(resolveInfos.get(0)) : null; } private static ComponentName resolveImplicitActivityIntent(PackageManager pm, Intent intent) { // Flag explanations. // - MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE: // Filter apps regardless of the phone's locked/unlocked state. // - MATCH_DEFAULT_ONLY: // Implicit intent receiver should be set as default. Only needed for activity. // - GET_ACTIVITIES: Return activity return createComponentName(pm.resolveActivity(intent, PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE | PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_ACTIVITIES)); } private static ComponentName createComponentName(ResolveInfo resolveInfo) { if (resolveInfo == null) { return null; } ComponentInfo componentInfo; // Code borrowed from ResolveInfo#getComponentInfo(). if (resolveInfo.activityInfo != null) { componentInfo = resolveInfo.activityInfo; } else if (resolveInfo.serviceInfo != null) { componentInfo = resolveInfo.serviceInfo; } else { // We're not interested in content provider. return null; } // Code borrowed from ComponentInfo#getComponentName(). try { return new ComponentName(componentInfo.packageName, componentInfo.name); } catch (IllegalArgumentException | NullPointerException e) { // This may be happen if resolveActivity() end up with matching multiple activities. // see PackageManager#resolveActivity(). return null; } } } services/core/java/com/android/server/media/MediaSessionRecord.java +10 −9 Original line number Diff line number Diff line Loading @@ -127,7 +127,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR new ArrayList<>(); private long mFlags; private PendingIntent mMediaButtonReceiver; private MediaButtonReceiverHolder mMediaButtonReceiverHolder; private PendingIntent mLaunchIntent; // TransportPerformer fields Loading Loading @@ -220,8 +220,8 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR * * @return The pending intent set by the app or null. */ public PendingIntent getMediaButtonReceiver() { return mMediaButtonReceiver; public MediaButtonReceiverHolder getMediaButtonReceiver() { return mMediaButtonReceiverHolder; } /** Loading Loading @@ -471,7 +471,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR + ", userId=" + mUserId); pw.println(indent + "package=" + mPackageName); pw.println(indent + "launchIntent=" + mLaunchIntent); pw.println(indent + "mediaButtonReceiver=" + mMediaButtonReceiver); pw.println(indent + "mediaButtonReceiver=" + mMediaButtonReceiverHolder); pw.println(indent + "active=" + mIsActive); pw.println(indent + "flags=" + mFlags); pw.println(indent + "rating type=" + mRatingType); Loading Loading @@ -833,12 +833,14 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR @Override public void setMediaButtonReceiver(PendingIntent pi) throws RemoteException { if ((mPolicies & SessionPolicyProvider.SESSION_POLICY_IGNORE_BUTTON_RECEIVER) == 1) { return; } mMediaButtonReceiver = pi; final long token = Binder.clearCallingIdentity(); try { if ((mPolicies & SessionPolicyProvider.SESSION_POLICY_IGNORE_BUTTON_RECEIVER) != 0) { return; } mMediaButtonReceiverHolder = MediaButtonReceiverHolder.create(mContext, mUserId, pi); mService.onMediaButtonReceiverChanged(MediaSessionRecord.this); } finally { Binder.restoreCallingIdentity(token); Loading Loading @@ -1529,5 +1531,4 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR msg.sendToTarget(); } } } services/core/java/com/android/server/media/MediaSessionService.java +32 −157 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
media/java/android/media/session/MediaSession.java +4 −0 Original line number Diff line number Diff line Loading @@ -266,8 +266,12 @@ public final class MediaSession { * playback after the session has been stopped. If your app is started in * this way an {@link Intent#ACTION_MEDIA_BUTTON} intent will be sent via * the pending intent. * <p> * The pending intent is recommended to be explicit to follow the security recommendation of * {@link PendingIntent#getActivity}. * * @param mbr The {@link PendingIntent} to send the media button event to. * @see PendingIntent#getActivity */ public void setMediaButtonReceiver(@Nullable PendingIntent mbr) { try { Loading
services/core/java/com/android/server/media/MediaButtonReceiverHolder.java 0 → 100644 +360 −0 Original line number Diff line number Diff line /* * Copyright 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.media; import android.annotation.IntDef; import android.annotation.NonNull; import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ComponentInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.os.Handler; import android.os.UserHandle; import android.text.TextUtils; import android.util.Log; import android.view.KeyEvent; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.List; /** * Holds the media button receiver, and also provides helper methods around it. */ final class MediaButtonReceiverHolder { public static final int COMPONENT_TYPE_INVALID = 0; public static final int COMPONENT_TYPE_BROADCAST = 1; public static final int COMPONENT_TYPE_ACTIVITY = 2; public static final int COMPONENT_TYPE_SERVICE = 3; @IntDef(value = { COMPONENT_TYPE_INVALID, COMPONENT_TYPE_BROADCAST, COMPONENT_TYPE_ACTIVITY, COMPONENT_TYPE_SERVICE, }) @Retention(RetentionPolicy.SOURCE) public @interface ComponentType {} private static final String TAG = "PendingIntentHolder"; private static final boolean DEBUG_KEY_EVENT = MediaSessionService.DEBUG_KEY_EVENT; private static final String COMPONENT_NAME_USER_ID_DELIM = ","; private final int mUserId; private final PendingIntent mPendingIntent; private final ComponentName mComponentName; private final String mPackageName; @ComponentType private final int mComponentType; /** * Unflatten from string which is previously flattened string via flattenToString(). * <p> * It's used to store and restore media button receiver across the boot, by keeping the intent's * component name to the persistent storage. * * @param mediaButtonReceiverInfo previously flattened string via flattenToString() * @return new instance if the string was valid. {@code null} otherwise. */ public static MediaButtonReceiverHolder unflattenFromString( Context context, String mediaButtonReceiverInfo) { if (TextUtils.isEmpty(mediaButtonReceiverInfo)) { return null; } String[] tokens = mediaButtonReceiverInfo.split(COMPONENT_NAME_USER_ID_DELIM); if (tokens == null || (tokens.length != 2 && tokens.length != 3)) { return null; } ComponentName componentName = ComponentName.unflattenFromString(tokens[0]); int userId = Integer.parseInt(tokens[1]); // Guess component type if the OS version is updated from the older version. int componentType = (tokens.length == 3) ? Integer.parseInt(tokens[2]) : getComponentType(context, componentName); return new MediaButtonReceiverHolder(userId, null, componentName, componentType); } /** * Creates a new instance. * * @param context context * @param userId userId * @param pendingIntent pending intent * @return Can be {@code null} if pending intent was null. */ public static MediaButtonReceiverHolder create(Context context, int userId, PendingIntent pendingIntent) { if (pendingIntent == null) { return null; } ComponentName componentName = (pendingIntent != null && pendingIntent.getIntent() != null) ? pendingIntent.getIntent().getComponent() : null; if (componentName != null) { // Explicit intent, where component name is in the PendingIntent. return new MediaButtonReceiverHolder(userId, pendingIntent, componentName, getComponentType(context, componentName)); } // Implicit intent, where component name isn't in the PendingIntent. Try resolve. PackageManager pm = context.getPackageManager(); Intent intent = pendingIntent.getIntent(); if ((componentName = resolveImplicitServiceIntent(pm, intent)) != null) { return new MediaButtonReceiverHolder( userId, pendingIntent, componentName, COMPONENT_TYPE_SERVICE); } else if ((componentName = resolveManifestDeclaredBroadcastReceiverIntent(pm, intent)) != null) { return new MediaButtonReceiverHolder( userId, pendingIntent, componentName, COMPONENT_TYPE_BROADCAST); } else if ((componentName = resolveImplicitActivityIntent(pm, intent)) != null) { return new MediaButtonReceiverHolder( userId, pendingIntent, componentName, COMPONENT_TYPE_ACTIVITY); } // Failed to resolve target component for the pending intent. It's unlikely to be usable. // However, the pending intent would be still used, just to follow the legacy behavior. Log.w(TAG, "Unresolvable implicit intent is set, pi=" + pendingIntent); String packageName = (pendingIntent != null && pendingIntent.getIntent() != null) ? pendingIntent.getIntent().getPackage() : null; return new MediaButtonReceiverHolder(userId, pendingIntent, packageName != null ? packageName : ""); } private MediaButtonReceiverHolder(int userId, PendingIntent pendingIntent, ComponentName componentName, @ComponentType int componentType) { mUserId = userId; mPendingIntent = pendingIntent; mComponentName = componentName; mPackageName = componentName.getPackageName(); mComponentType = componentType; } private MediaButtonReceiverHolder(int userId, PendingIntent pendingIntent, String packageName) { mUserId = userId; mPendingIntent = pendingIntent; mComponentName = null; mPackageName = packageName; mComponentType = COMPONENT_TYPE_INVALID; } /** * @return the user id */ public int getUserId() { return mUserId; } /** * @return package name that the media button receiver would be sent to. */ @NonNull public String getPackageName() { return mPackageName; } /** * Sends the media key event to the media button receiver. * <p> * This prioritizes using use pending intent for sending media key event. * * @param context context to be used to call PendingIntent#send * @param keyEvent keyEvent to send * @param resultCode result code to be used to call PendingIntent#send * Ignored if there's no valid pending intent. * @param onFinishedListener callback to be used to get result of PendingIntent#send. * Ignored if there's no valid pending intent. * @param handler handler to be used to call onFinishedListener * Ignored if there's no valid pending intent. * @see PendingIntent#send(Context, int, Intent, PendingIntent.OnFinished, Handler) */ public boolean send(Context context, KeyEvent keyEvent, String callingPackageName, int resultCode, PendingIntent.OnFinished onFinishedListener, Handler handler) { Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); mediaButtonIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent); // TODO: Find a way to also send PID/UID in secure way. mediaButtonIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, callingPackageName); if (mPendingIntent != null) { if (DEBUG_KEY_EVENT) { Log.d(TAG, "Sending " + keyEvent + " to the last known PendingIntent " + mPendingIntent); } try { mPendingIntent.send( context, resultCode, mediaButtonIntent, onFinishedListener, handler); } catch (PendingIntent.CanceledException e) { Log.w(TAG, "Error sending key event to media button receiver " + mPendingIntent, e); return false; } } else if (mComponentName != null) { if (DEBUG_KEY_EVENT) { Log.d(TAG, "Sending " + keyEvent + " to the restored intent " + mComponentName + ", type=" + mComponentType); } mediaButtonIntent.setComponent(mComponentName); UserHandle userHandle = UserHandle.of(mUserId); try { switch (mComponentType) { case COMPONENT_TYPE_ACTIVITY: context.startActivityAsUser(mediaButtonIntent, userHandle); break; case COMPONENT_TYPE_SERVICE: context.startForegroundServiceAsUser(mediaButtonIntent, userHandle); break; default: // Legacy behavior for other cases. context.sendBroadcastAsUser(mediaButtonIntent, userHandle); } } catch (Exception e) { Log.w(TAG, "Error sending media button to the restored intent " + mComponentName + ", type=" + mComponentType, e); return false; } } else { // Leave log, just in case. Log.e(TAG, "Shouldn't be happen -- pending intent or component name must be set"); return false; } return true; } @Override public String toString() { if (mPendingIntent != null) { return "MBR {pi=" + mPendingIntent + ", type=" + mComponentType + "}"; } return "Restored MBR {component=" + mComponentName + ", type=" + mComponentType + "}"; } /** * @return flattened string. Can be empty string if the MBR is created with implicit intent. */ public String flattenToString() { if (mComponentName == null) { // We don't know which component would receive the key event. return ""; } return String.join(COMPONENT_NAME_USER_ID_DELIM, mComponentName.toString(), String.valueOf(mUserId), String.valueOf(mComponentType)); } /** * Gets the type of the component * * @param context context * @param componentName component name * @return A component type */ @ComponentType private static int getComponentType(Context context, ComponentName componentName) { if (componentName == null) { return COMPONENT_TYPE_INVALID; } PackageManager pm = context.getPackageManager(); try { ActivityInfo activityInfo = pm.getActivityInfo(componentName, PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE | PackageManager.GET_ACTIVITIES); if (activityInfo != null) { return COMPONENT_TYPE_ACTIVITY; } } catch (PackageManager.NameNotFoundException e) { } try { ServiceInfo serviceInfo = pm.getServiceInfo(componentName, PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE | PackageManager.GET_SERVICES); if (serviceInfo != null) { return COMPONENT_TYPE_SERVICE; } } catch (PackageManager.NameNotFoundException e) { } // Pick legacy behavior for BroadcastReceiver or unknown. return COMPONENT_TYPE_BROADCAST; } private static ComponentName resolveImplicitServiceIntent(PackageManager pm, Intent intent) { // Flag explanations. // - MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE: // filter apps regardless of the phone's locked/unlocked state. // - GET_SERVICES: Return service return createComponentName(pm.resolveService(intent, PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE | PackageManager.GET_SERVICES)); } private static ComponentName resolveManifestDeclaredBroadcastReceiverIntent( PackageManager pm, Intent intent) { // Flag explanations. // - MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE: // filter apps regardless of the phone's locked/unlocked state. List<ResolveInfo> resolveInfos = pm.queryBroadcastReceivers(intent, PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE); return (resolveInfos != null && !resolveInfos.isEmpty()) ? createComponentName(resolveInfos.get(0)) : null; } private static ComponentName resolveImplicitActivityIntent(PackageManager pm, Intent intent) { // Flag explanations. // - MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE: // Filter apps regardless of the phone's locked/unlocked state. // - MATCH_DEFAULT_ONLY: // Implicit intent receiver should be set as default. Only needed for activity. // - GET_ACTIVITIES: Return activity return createComponentName(pm.resolveActivity(intent, PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE | PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_ACTIVITIES)); } private static ComponentName createComponentName(ResolveInfo resolveInfo) { if (resolveInfo == null) { return null; } ComponentInfo componentInfo; // Code borrowed from ResolveInfo#getComponentInfo(). if (resolveInfo.activityInfo != null) { componentInfo = resolveInfo.activityInfo; } else if (resolveInfo.serviceInfo != null) { componentInfo = resolveInfo.serviceInfo; } else { // We're not interested in content provider. return null; } // Code borrowed from ComponentInfo#getComponentName(). try { return new ComponentName(componentInfo.packageName, componentInfo.name); } catch (IllegalArgumentException | NullPointerException e) { // This may be happen if resolveActivity() end up with matching multiple activities. // see PackageManager#resolveActivity(). return null; } } }
services/core/java/com/android/server/media/MediaSessionRecord.java +10 −9 Original line number Diff line number Diff line Loading @@ -127,7 +127,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR new ArrayList<>(); private long mFlags; private PendingIntent mMediaButtonReceiver; private MediaButtonReceiverHolder mMediaButtonReceiverHolder; private PendingIntent mLaunchIntent; // TransportPerformer fields Loading Loading @@ -220,8 +220,8 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR * * @return The pending intent set by the app or null. */ public PendingIntent getMediaButtonReceiver() { return mMediaButtonReceiver; public MediaButtonReceiverHolder getMediaButtonReceiver() { return mMediaButtonReceiverHolder; } /** Loading Loading @@ -471,7 +471,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR + ", userId=" + mUserId); pw.println(indent + "package=" + mPackageName); pw.println(indent + "launchIntent=" + mLaunchIntent); pw.println(indent + "mediaButtonReceiver=" + mMediaButtonReceiver); pw.println(indent + "mediaButtonReceiver=" + mMediaButtonReceiverHolder); pw.println(indent + "active=" + mIsActive); pw.println(indent + "flags=" + mFlags); pw.println(indent + "rating type=" + mRatingType); Loading Loading @@ -833,12 +833,14 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR @Override public void setMediaButtonReceiver(PendingIntent pi) throws RemoteException { if ((mPolicies & SessionPolicyProvider.SESSION_POLICY_IGNORE_BUTTON_RECEIVER) == 1) { return; } mMediaButtonReceiver = pi; final long token = Binder.clearCallingIdentity(); try { if ((mPolicies & SessionPolicyProvider.SESSION_POLICY_IGNORE_BUTTON_RECEIVER) != 0) { return; } mMediaButtonReceiverHolder = MediaButtonReceiverHolder.create(mContext, mUserId, pi); mService.onMediaButtonReceiverChanged(MediaSessionRecord.this); } finally { Binder.restoreCallingIdentity(token); Loading Loading @@ -1529,5 +1531,4 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR msg.sendToTarget(); } } }
services/core/java/com/android/server/media/MediaSessionService.java +32 −157 File changed.Preview size limit exceeded, changes collapsed. Show changes