DO NOT MERGE) MediaBrowserCompat: Fix for sending messages to a remote process

- In order to send an object via Message.obj from a process to
  a different process, the type of the object should be parcelable.
- When using Messenger, Binder.getCallingUid() in handleMessage does
  not return the uid of the calling process.

Bug: 26609825
Change-Id: I1f9ad5b46e8e174600eb432bf91e7541900b6283
diff --git a/v4/java/android/support/v4/media/MediaBrowserCompat.java b/v4/java/android/support/v4/media/MediaBrowserCompat.java
index f60d596..c6bad63 100644
--- a/v4/java/android/support/v4/media/MediaBrowserCompat.java
+++ b/v4/java/android/support/v4/media/MediaBrowserCompat.java
@@ -916,34 +916,40 @@
             }
 
             void connect() throws RemoteException {
-                sendRequest(CLIENT_MSG_CONNECT, mContext.getPackageName(), mRootHints,
-                        mCallbacksMessenger);
+                Bundle data = new Bundle();
+                data.putString(DATA_PACKAGE_NAME, mContext.getPackageName());
+                data.putBundle(DATA_ROOT_HINTS, mRootHints);
+                sendRequest(CLIENT_MSG_CONNECT, data, mCallbacksMessenger);
             }
 
             void disconnect() throws RemoteException {
-                sendRequest(CLIENT_MSG_DISCONNECT, null, null, mCallbacksMessenger);
+                sendRequest(CLIENT_MSG_DISCONNECT, null, mCallbacksMessenger);
             }
 
             void addSubscription(String parentId) throws RemoteException {
-                sendRequest(CLIENT_MSG_ADD_SUBSCRIPTION, parentId, null, mCallbacksMessenger);
+                Bundle data = new Bundle();
+                data.putString(DATA_MEDIA_ITEM_ID, parentId);
+                sendRequest(CLIENT_MSG_ADD_SUBSCRIPTION, data, mCallbacksMessenger);
             }
 
             void removeSubscription(String parentId) throws RemoteException {
-                sendRequest(CLIENT_MSG_REMOVE_SUBSCRIPTION, parentId, null, mCallbacksMessenger);
+                Bundle data = new Bundle();
+                data.putString(DATA_MEDIA_ITEM_ID, parentId);
+                sendRequest(CLIENT_MSG_REMOVE_SUBSCRIPTION, data, mCallbacksMessenger);
             }
 
             void getMediaItem(String mediaId, ResultReceiver receiver) throws RemoteException {
                 Bundle data = new Bundle();
-                data.putParcelable(SERVICE_DATA_RESULT_RECEIVER, receiver);
-                sendRequest(CLIENT_MSG_GET_MEDIA_ITEM, mediaId, data, null);
+                data.putString(DATA_MEDIA_ITEM_ID, mediaId);
+                data.putParcelable(DATA_RESULT_RECEIVER, receiver);
+                sendRequest(CLIENT_MSG_GET_MEDIA_ITEM, data, null);
             }
 
-            private void sendRequest(int what, Object obj, Bundle data, Messenger cbMessenger)
+            private void sendRequest(int what, Bundle data, Messenger cbMessenger)
                     throws RemoteException {
                 Message msg = Message.obtain();
                 msg.what = what;
                 msg.arg1 = CLIENT_VERSION_CURRENT;
-                msg.obj = obj;
                 msg.setData(data);
                 msg.replyTo = cbMessenger;
                 mMessenger.send(msg);
@@ -1062,17 +1068,17 @@
                 Bundle data = msg.getData();
                 switch (msg.what) {
                     case SERVICE_MSG_ON_CONNECT:
-                        onServiceConnected(mCallbacksMessenger, (String) msg.obj,
+                        onServiceConnected(mCallbacksMessenger, data.getString(DATA_MEDIA_ITEM_ID),
                                 (MediaSessionCompat.Token) data.getParcelable(
-                                        SERVICE_DATA_MEDIA_SESSION_TOKEN),
-                                data.getBundle(SERVICE_DATA_EXTRAS));
+                                        DATA_MEDIA_SESSION_TOKEN),
+                                data.getBundle(DATA_ROOT_HINTS));
                         break;
                     case SERVICE_MSG_ON_CONNECT_FAILED:
                         onConnectionFailed(mCallbacksMessenger);
                         break;
                     case SERVICE_MSG_ON_LOAD_CHILDREN:
-                        onLoadChildren(mCallbacksMessenger,  (String) msg.obj,
-                                data.getParcelableArrayList(SERVICE_DATA_MEDIA_ITEM_LIST));
+                        onLoadChildren(mCallbacksMessenger,  data.getString(DATA_MEDIA_ITEM_ID),
+                                data.getParcelableArrayList(DATA_MEDIA_ITEM_LIST));
                         break;
                     default:
                         Log.w(TAG, "Unhandled message: " + msg
@@ -1207,7 +1213,7 @@
             };
             try {
                 Bundle data = new Bundle();
-                data.putParcelable(SERVICE_DATA_RESULT_RECEIVER, receiver);
+                data.putParcelable(DATA_RESULT_RECEIVER, receiver);
                 sendRequest(CLIENT_MSG_GET_MEDIA_ITEM, mediaId, data, null);
             } catch (RemoteException e) {
                 Log.i(TAG, "Remote error getting media item.");
diff --git a/v4/java/android/support/v4/media/MediaBrowserProtocol.java b/v4/java/android/support/v4/media/MediaBrowserProtocol.java
index 7c8feb3..6410466 100644
--- a/v4/java/android/support/v4/media/MediaBrowserProtocol.java
+++ b/v4/java/android/support/v4/media/MediaBrowserProtocol.java
@@ -21,6 +21,17 @@
  */
 class MediaBrowserProtocol {
 
+    public static final String DATA_CALLING_UID = "data_calling_uid";
+    public static final String DATA_ROOT_HINTS = "data_root_hints";
+    public static final String DATA_MEDIA_ITEM_ID = "data_media_item_id";
+    public static final String DATA_MEDIA_ITEM_LIST = "data_media_item_list";
+    public static final String DATA_MEDIA_SESSION_TOKEN = "data_media_session_token";
+    public static final String DATA_PACKAGE_NAME = "data_package_name";
+    public static final String DATA_RESULT_RECEIVER = "data_result_receiver";
+
+    public static final String EXTRA_SERVICE_VERSION = "extra_service_version";
+    public static final String EXTRA_MESSENGER_BINDER = "extra_messenger";
+
     /**
      * MediaBrowserCompat will check the version of the connected MediaBrowserServiceCompat,
      * and it will not send messages if they are introduced in the higher version of the
@@ -39,10 +50,10 @@
      * Sent after {@link MediaBrowserCompat#connect()} when the request has successfully
      * completed.
      * - arg1 : The service version
-     * - obj  : The root media item id
      * - data
-     *     SERVICE_DATA_MEDIA_SESSION_TOKEN : Media session token
-     *     SERVICE_DATA_EXTRAS : An extras bundle which contains EXTRA_SERVICE_VERSION
+     *     DATA_MEDIA_ITEM_ID : A string for the root media item id
+     *     DATA_MEDIA_SESSION_TOKEN : Media session token
+     *     DATA_ROOT_HINTS : An extras bundle which contains EXTRA_SERVICE_VERSION
      */
     public static final int SERVICE_MSG_ON_CONNECT = 1;
 
@@ -56,20 +67,12 @@
     /** (service v1)
      * Sent when the list of children is loaded or updated.
      * - arg1 : The service version
-     * - obj  : The parent media item id
      * - data
-     *     SERVICE_DATA_MEDIA_ITEM_LIST : An array list for the media item children
+     *     DATA_MEDIA_ITEM_ID : A string for the parent media item id
+     *     DATA_MEDIA_ITEM_LIST : An array list for the media item children
      */
     public static final int SERVICE_MSG_ON_LOAD_CHILDREN = 3;
 
-    public static final String SERVICE_DATA_MEDIA_SESSION_TOKEN = "data_media_session_token";
-    public static final String SERVICE_DATA_EXTRAS = "data_extras";
-    public static final String SERVICE_DATA_MEDIA_ITEM_LIST = "data_media_item_list";
-    public static final String SERVICE_DATA_RESULT_RECEIVER = "data_result_receiver";
-
-    public static final String EXTRA_SERVICE_VERSION = "extra_service_version";
-    public static final String EXTRA_MESSENGER_BINDER = "extra_messenger";
-
     /**
      * MediaBrowserServiceCompat will check the version of the MediaBrowserCompat, and it will not
      * send messages if they are introduced in the higher version of the MediaBrowserCompat.
@@ -87,7 +90,9 @@
      * Sent to connect to the media browse service compat.
      * - arg1 : The client version
      * - obj  : The package name
-     * - data : An optional root hints bundle of service-specific arguments
+     * - data
+     *     DATA_PACKAGE_NAME : A string for the package name of MediaBrowserCompat
+     *     DATA_ROOT_HINTS : An optional root hints bundle of service-specific arguments
      * - replayTo : Client messenger
      */
     public static final int CLIENT_MSG_CONNECT = 1;
@@ -102,7 +107,8 @@
     /** (client v1)
      * Sent to subscribe for changes to the children of the specified media id.
      * - arg1 : The client version
-     * - obj  : The media item id
+     * - data
+     *     DATA_MEDIA_ITEM_ID : A string for a media item id
      * - replayTo : Client messenger
      */
     public static final int CLIENT_MSG_ADD_SUBSCRIPTION = 3;
@@ -110,7 +116,8 @@
     /** (client v1)
      * Sent to unsubscribe for changes to the children of the specified media id.
      * - arg1 : The client version
-     * - obj  : The media item id
+     * - data
+     *     DATA_MEDIA_ITEM_ID : A string for a media item id
      * - replayTo : Client messenger
      */
     public static final int CLIENT_MSG_REMOVE_SUBSCRIPTION = 4;
@@ -118,9 +125,9 @@
     /** (client v1)
      * Sent to retrieves a specific media item from the connected service.
      * - arg1 : The client version
-     * - obj  : The media item id
      * - data
-     *     SERVICE_DATA_RESULT_RECEIVER : Result receiver to get the result
+     *     DATA_MEDIA_ITEM_ID : A string for a media item id
+     *     DATA_RESULT_RECEIVER : Result receiver to get the result
      */
     public static final int CLIENT_MSG_GET_MEDIA_ITEM = 5;
 }
diff --git a/v4/java/android/support/v4/media/MediaBrowserServiceCompat.java b/v4/java/android/support/v4/media/MediaBrowserServiceCompat.java
index 90a361e..587329d 100644
--- a/v4/java/android/support/v4/media/MediaBrowserServiceCompat.java
+++ b/v4/java/android/support/v4/media/MediaBrowserServiceCompat.java
@@ -145,25 +145,27 @@
 
         @Override
         public void handleMessage(Message msg) {
+            Bundle data = msg.getData();
             switch (msg.what) {
                 case CLIENT_MSG_CONNECT:
-                    mServiceImpl.connect((String) msg.obj, msg.getData(),
+                    mServiceImpl.connect(data.getString(DATA_PACKAGE_NAME),
+                            data.getInt(DATA_CALLING_UID), data.getBundle(DATA_ROOT_HINTS),
                             new ServiceCallbacksCompat(msg.replyTo));
                     break;
                 case CLIENT_MSG_DISCONNECT:
                     mServiceImpl.disconnect(new ServiceCallbacksCompat(msg.replyTo));
                     break;
                 case CLIENT_MSG_ADD_SUBSCRIPTION:
-                    mServiceImpl.addSubscription((String) msg.obj,
+                    mServiceImpl.addSubscription(data.getString(DATA_MEDIA_ITEM_ID),
                             new ServiceCallbacksCompat(msg.replyTo));
                     break;
                 case CLIENT_MSG_REMOVE_SUBSCRIPTION:
-                    mServiceImpl.removeSubscription((String) msg.obj,
+                    mServiceImpl.removeSubscription(data.getString(DATA_MEDIA_ITEM_ID),
                             new ServiceCallbacksCompat(msg.replyTo));
                     break;
                 case CLIENT_MSG_GET_MEDIA_ITEM:
-                    mServiceImpl.getMediaItem((String) msg.obj, (ResultReceiver) msg.getData()
-                            .getParcelable(SERVICE_DATA_RESULT_RECEIVER));
+                    mServiceImpl.getMediaItem(data.getString(DATA_MEDIA_ITEM_ID),
+                            (ResultReceiver) data.getParcelable(DATA_RESULT_RECEIVER));
                     break;
                 default:
                     Log.w(TAG, "Unhandled message: " + msg
@@ -172,6 +174,15 @@
             }
         }
 
+        @Override
+        public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
+            // Binder.getCallingUid() in handleMessage will return the uid of this process.
+            // In order to get the right calling uid, Binder.getCallingUid() should be called here.
+            Bundle data = msg.getData();
+            data.putInt(DATA_CALLING_UID, Binder.getCallingUid());
+            return super.sendMessageAtTime(msg, uptimeMillis);
+        }
+
         public void postOrRun(Runnable r) {
             if (Thread.currentThread() == getLooper().getThread()) {
                 r.run();
@@ -258,10 +269,9 @@
     }
 
     private class ServiceImpl {
-        public void connect(final String pkg, final Bundle rootHints,
+        public void connect(final String pkg, final int uid, final Bundle rootHints,
                 final ServiceCallbacks callbacks) {
 
-            final int uid = Binder.getCallingUid();
             if (!isValidPackage(pkg, uid)) {
                 throw new IllegalArgumentException("Package/uid mismatch: uid=" + uid
                         + " package=" + pkg);
@@ -389,7 +399,8 @@
         @Override
         public void connect(final String pkg, final Bundle rootHints,
                 final MediaBrowserServiceCompatApi21.ServiceCallbacks callbacks) {
-            mServiceImpl.connect(pkg, rootHints, new ServiceCallbacksApi21(callbacks));
+            mServiceImpl.connect(pkg, Binder.getCallingUid(), rootHints,
+                    new ServiceCallbacksApi21(callbacks));
         }
 
         @Override
@@ -459,32 +470,31 @@
             }
             extras.putInt(EXTRA_SERVICE_VERSION, SERVICE_VERSION_CURRENT);
             Bundle data = new Bundle();
-            data.putParcelable(SERVICE_DATA_MEDIA_SESSION_TOKEN, session);
-            data.putBundle(SERVICE_DATA_EXTRAS, extras);
-            sendRequest(SERVICE_MSG_ON_CONNECT, root, data);
+            data.putString(DATA_MEDIA_ITEM_ID, root);
+            data.putParcelable(DATA_MEDIA_SESSION_TOKEN, session);
+            data.putBundle(DATA_ROOT_HINTS, extras);
+            sendRequest(SERVICE_MSG_ON_CONNECT, data);
         }
 
         public void onConnectFailed() throws RemoteException {
-            sendRequest(SERVICE_MSG_ON_CONNECT_FAILED, null, null);
+            sendRequest(SERVICE_MSG_ON_CONNECT_FAILED, null);
         }
 
         public void onLoadChildren(String mediaId, List<MediaBrowserCompat.MediaItem> list)
                 throws RemoteException {
-            Bundle data = null;
+            Bundle data = new Bundle();
+            data.putString(DATA_MEDIA_ITEM_ID, mediaId);
             if (list != null) {
-                data = new Bundle();
-                data.putParcelableArrayList(SERVICE_DATA_MEDIA_ITEM_LIST,
+                data.putParcelableArrayList(DATA_MEDIA_ITEM_LIST,
                         list instanceof ArrayList ? (ArrayList) list : new ArrayList<>(list));
             }
-            sendRequest(SERVICE_MSG_ON_LOAD_CHILDREN, mediaId, data);
+            sendRequest(SERVICE_MSG_ON_LOAD_CHILDREN, data);
         }
 
-        private void sendRequest(int what, Object obj, Bundle data)
-                throws RemoteException {
+        private void sendRequest(int what, Bundle data) throws RemoteException {
             Message msg = Message.obtain();
             msg.what = what;
             msg.arg1 = SERVICE_VERSION_CURRENT;
-            msg.obj = obj;
             msg.setData(data);
             mCallbacks.send(msg);
         }