summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/companion/CompanionDeviceManager.java147
-rw-r--r--core/java/android/companion/ICompanionDeviceManager.aidl12
-rw-r--r--core/java/android/companion/IOnMessageReceivedListener.aidl23
-rw-r--r--core/java/android/companion/IOnTransportsChangedListener.aidl25
-rw-r--r--services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java35
-rw-r--r--services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java16
-rw-r--r--services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java164
-rw-r--r--services/companion/java/com/android/server/companion/transport/Transport.java42
8 files changed, 424 insertions, 40 deletions
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index de4f619392c1..a522cc04eff1 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -801,6 +801,119 @@ public final class CompanionDeviceManager {
}
/**
+ * Listener for any changes to {@link com.android.server.companion.transport.Transport}.
+ *
+ * @hide
+ */
+ public interface OnTransportsChangedListener {
+ /**
+ * Invoked when a change occurs to any of the transports
+ *
+ * @param associations all the associations which have connected transports
+ */
+ void onTransportsChanged(@NonNull List<AssociationInfo> associations);
+ }
+
+ /**
+ * Register a listener for any changes to
+ * {@link com.android.server.companion.transport.Transport}. Your app will receive a callback to
+ * {@link OnTransportsChangedListener} immediately with all the existing transports.
+ *
+ * @hide
+ */
+ public void addOnTransportsChangedListener(
+ @NonNull Executor executor, @NonNull OnTransportsChangedListener listener) {
+ final OnTransportsChangedListenerProxy proxy = new OnTransportsChangedListenerProxy(
+ executor, listener);
+ try {
+ mService.addOnTransportsChangedListener(proxy);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Unregister a listener to stop receiving any changes to
+ * {@link com.android.server.companion.transport.Transport}.
+ *
+ * @hide
+ */
+ public void removeOnTransportsChangedListener(
+ @NonNull OnTransportsChangedListener listener) {
+ final OnTransportsChangedListenerProxy proxy = new OnTransportsChangedListenerProxy(
+ null, listener);
+ try {
+ mService.removeOnTransportsChangedListener(proxy);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Send a message to remote devices
+ *
+ * @hide
+ */
+ public void sendMessage(int messageType, byte[] data, int[] associationIds) {
+ try {
+ mService.sendMessage(messageType, data, associationIds);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Listener when a message is received for the registered message type
+ *
+ * @see #addOnMessageReceivedListener(Executor, int, OnMessageReceivedListener)
+ *
+ * @hide
+ */
+ public interface OnMessageReceivedListener {
+ /**
+ * Called when a message is received
+ */
+ void onMessageReceived(int associationId, byte[] data);
+ }
+
+ /**
+ * Register a listener to receive callbacks when a message is received by the given type
+ *
+ * @see com.android.server.companion.transport.Transport for supported message types
+ *
+ * @hide
+ */
+ public void addOnMessageReceivedListener(@NonNull Executor executor, int messageType,
+ OnMessageReceivedListener listener) {
+ final OnMessageReceivedListenerProxy proxy = new OnMessageReceivedListenerProxy(
+ executor, listener);
+ try {
+ mService.addOnMessageReceivedListener(messageType, proxy);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Unregister a listener to stop receiving callbacks when a message is received by the given
+ * type
+ *
+ * @see com.android.server.companion.transport.Transport for supported message types
+ *
+ * @hide
+ */
+ public void removeOnMessageReceivedListener(int messageType,
+ OnMessageReceivedListener listener) {
+ final OnMessageReceivedListenerProxy proxy = new OnMessageReceivedListenerProxy(
+ null, listener);
+ try {
+ mService.removeOnMessageReceivedListener(messageType, proxy);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Checks whether the bluetooth device represented by the mac address was recently associated
* with the companion app. This allows these devices to skip the Bluetooth pairing dialog if
* their pairing variant is {@link BluetoothDevice#PAIRING_VARIANT_CONSENT}.
@@ -1277,6 +1390,40 @@ public final class CompanionDeviceManager {
}
}
+ private static class OnTransportsChangedListenerProxy
+ extends IOnTransportsChangedListener.Stub {
+ private final Executor mExecutor;
+ private final OnTransportsChangedListener mListener;
+
+ private OnTransportsChangedListenerProxy(Executor executor,
+ OnTransportsChangedListener listener) {
+ mExecutor = executor;
+ mListener = listener;
+ }
+
+ @Override
+ public void onTransportsChanged(@NonNull List<AssociationInfo> associations) {
+ mExecutor.execute(() -> mListener.onTransportsChanged(associations));
+ }
+ }
+
+ private static class OnMessageReceivedListenerProxy
+ extends IOnMessageReceivedListener.Stub {
+ private final Executor mExecutor;
+ private final OnMessageReceivedListener mListener;
+
+ private OnMessageReceivedListenerProxy(Executor executor,
+ OnMessageReceivedListener listener) {
+ mExecutor = executor;
+ mListener = listener;
+ }
+
+ @Override
+ public void onMessageReceived(int associationId, byte[] data) {
+ mExecutor.execute(() -> mListener.onMessageReceived(associationId, data));
+ }
+ }
+
private static class SystemDataTransferCallbackProxy extends ISystemDataTransferCallback.Stub {
private final Executor mExecutor;
private final OutcomeReceiver<Void, CompanionException> mCallback;
diff --git a/core/java/android/companion/ICompanionDeviceManager.aidl b/core/java/android/companion/ICompanionDeviceManager.aidl
index cb4baca73ba0..b5e2670e5299 100644
--- a/core/java/android/companion/ICompanionDeviceManager.aidl
+++ b/core/java/android/companion/ICompanionDeviceManager.aidl
@@ -19,6 +19,8 @@ package android.companion;
import android.app.PendingIntent;
import android.companion.IAssociationRequestCallback;
import android.companion.IOnAssociationsChangedListener;
+import android.companion.IOnMessageReceivedListener;
+import android.companion.IOnTransportsChangedListener;
import android.companion.ISystemDataTransferCallback;
import android.companion.AssociationInfo;
import android.companion.AssociationRequest;
@@ -67,6 +69,16 @@ interface ICompanionDeviceManager {
void removeOnAssociationsChangedListener(IOnAssociationsChangedListener listener, int userId);
+ void addOnTransportsChangedListener(IOnTransportsChangedListener listener);
+
+ void removeOnTransportsChangedListener(IOnTransportsChangedListener listener);
+
+ void sendMessage(int messageType, in byte[] data, in int[] associationIds);
+
+ void addOnMessageReceivedListener(int messageType, IOnMessageReceivedListener listener);
+
+ void removeOnMessageReceivedListener(int messageType, IOnMessageReceivedListener listener);
+
void notifyDeviceAppeared(int associationId);
void notifyDeviceDisappeared(int associationId);
diff --git a/core/java/android/companion/IOnMessageReceivedListener.aidl b/core/java/android/companion/IOnMessageReceivedListener.aidl
new file mode 100644
index 000000000000..17f03f80996e
--- /dev/null
+++ b/core/java/android/companion/IOnMessageReceivedListener.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2023 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 per missions and
+ * limitations under the License.
+ */
+
+package android.companion;
+
+/** @hide */
+interface IOnMessageReceivedListener {
+
+ oneway void onMessageReceived(int associationId, in byte[] data);
+} \ No newline at end of file
diff --git a/core/java/android/companion/IOnTransportsChangedListener.aidl b/core/java/android/companion/IOnTransportsChangedListener.aidl
new file mode 100644
index 000000000000..a10147627a9d
--- /dev/null
+++ b/core/java/android/companion/IOnTransportsChangedListener.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2023 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 per missions and
+ * limitations under the License.
+ */
+
+package android.companion;
+
+import android.companion.AssociationInfo;
+
+/** @hide */
+interface IOnTransportsChangedListener {
+
+ oneway void onTransportsChanged(in List<AssociationInfo> associations);
+} \ No newline at end of file
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index a35cae9dffda..542cc2f0a0a6 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -59,6 +59,8 @@ import android.companion.DeviceNotAssociatedException;
import android.companion.IAssociationRequestCallback;
import android.companion.ICompanionDeviceManager;
import android.companion.IOnAssociationsChangedListener;
+import android.companion.IOnMessageReceivedListener;
+import android.companion.IOnTransportsChangedListener;
import android.companion.ISystemDataTransferCallback;
import android.content.ComponentName;
import android.content.Context;
@@ -232,7 +234,7 @@ public class CompanionDeviceManagerService extends SystemService {
/* cdmService */this, mAssociationStore);
mCompanionAppController = new CompanionApplicationController(
context, mAssociationStore, mDevicePresenceMonitor);
- mTransportManager = new CompanionTransportManager(context);
+ mTransportManager = new CompanionTransportManager(context, mAssociationStore);
mSystemDataTransferProcessor = new SystemDataTransferProcessor(this, mAssociationStore,
mSystemDataTransferRequestStore, mTransportManager);
@@ -601,6 +603,37 @@ public class CompanionDeviceManagerService extends SystemService {
}
@Override
+ @GuardedBy("CompanionDeviceManagerService.this.mTransportManager.mTransports")
+ public void addOnTransportsChangedListener(IOnTransportsChangedListener listener) {
+ mTransportManager.addListener(listener);
+ }
+
+ @Override
+ @GuardedBy("CompanionDeviceManagerService.this.mTransportManager.mTransports")
+ public void removeOnTransportsChangedListener(IOnTransportsChangedListener listener) {
+ mTransportManager.removeListener(listener);
+ }
+
+ @Override
+ @GuardedBy("CompanionDeviceManagerService.this.mTransportManager.mTransports")
+ public void sendMessage(int messageType, byte[] data, int[] associationIds) {
+ mTransportManager.sendMessage(messageType, data, associationIds);
+ }
+
+ @Override
+ @GuardedBy("CompanionDeviceManagerService.this.mTransportManager.mTransports")
+ public void addOnMessageReceivedListener(int messageType,
+ IOnMessageReceivedListener listener) {
+ mTransportManager.addListener(messageType, listener);
+ }
+
+ @Override
+ public void removeOnMessageReceivedListener(int messageType,
+ IOnMessageReceivedListener listener) {
+ mTransportManager.removeListener(messageType, listener);
+ }
+
+ @Override
public void legacyDisassociate(String deviceMacAddress, String packageName, int userId) {
Log.i(TAG, "legacyDisassociate() pkg=u" + userId + "/" + packageName
+ ", macAddress=" + deviceMacAddress);
diff --git a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java
index 3fffdbecd0de..f3a949d29ff8 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java
@@ -31,6 +31,7 @@ import android.annotation.UserIdInt;
import android.app.PendingIntent;
import android.companion.AssociationInfo;
import android.companion.DeviceNotAssociatedException;
+import android.companion.IOnMessageReceivedListener;
import android.companion.ISystemDataTransferCallback;
import android.companion.datatransfer.PermissionSyncRequest;
import android.companion.datatransfer.SystemDataTransferRequest;
@@ -40,6 +41,7 @@ import android.content.Intent;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
+import android.os.IBinder;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.UserHandle;
@@ -92,8 +94,18 @@ public class SystemDataTransferProcessor {
mAssociationStore = associationStore;
mSystemDataTransferRequestStore = systemDataTransferRequestStore;
mTransportManager = transportManager;
- mTransportManager.addListener(MESSAGE_REQUEST_PERMISSION_RESTORE,
- this::onReceivePermissionRestore);
+ IOnMessageReceivedListener messageListener = new IOnMessageReceivedListener() {
+ @Override
+ public void onMessageReceived(int associationId, byte[] data) throws RemoteException {
+ onReceivePermissionRestore(data);
+ }
+
+ @Override
+ public IBinder asBinder() {
+ return null;
+ }
+ };
+ mTransportManager.addListener(MESSAGE_REQUEST_PERMISSION_RESTORE, messageListener);
mPermissionControllerManager = mContext.getSystemService(PermissionControllerManager.class);
mExecutor = Executors.newSingleThreadExecutor();
}
diff --git a/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java b/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java
index 8dab231d1819..539020519f84 100644
--- a/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java
+++ b/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java
@@ -22,25 +22,32 @@ import static com.android.server.companion.transport.Transport.MESSAGE_REQUEST_P
import static com.android.server.companion.transport.Transport.MESSAGE_REQUEST_PLATFORM_INFO;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.app.ActivityManagerInternal;
+import android.companion.AssociationInfo;
+import android.companion.IOnMessageReceivedListener;
+import android.companion.IOnTransportsChangedListener;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Binder;
import android.os.Build;
+import android.os.IBinder;
import android.os.ParcelFileDescriptor;
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
import android.util.Slog;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.server.LocalServices;
-import com.android.server.companion.transport.Transport.Listener;
+import com.android.server.companion.AssociationStore;
import java.io.IOException;
import java.nio.ByteBuffer;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
@@ -63,31 +70,100 @@ public class CompanionTransportManager {
}
private final Context mContext;
+ private final AssociationStore mAssociationStore;
+ /** Association id -> Transport */
@GuardedBy("mTransports")
private final SparseArray<Transport> mTransports = new SparseArray<>();
-
@NonNull
- private final Map<Integer, Listener> mListeners = new HashMap<>();
+ private final RemoteCallbackList<IOnTransportsChangedListener> mTransportsListeners =
+ new RemoteCallbackList<>();
+ /** Message type -> IOnMessageReceivedListener */
+ @NonNull
+ private final SparseArray<IOnMessageReceivedListener> mMessageListeners = new SparseArray<>();
+
+ @Nullable
private Transport mTempTransport;
- public CompanionTransportManager(Context context) {
+ public CompanionTransportManager(Context context, AssociationStore associationStore) {
mContext = context;
+ mAssociationStore = associationStore;
}
/**
- * Add a message listener when a message is received for the message type
+ * Add a listener to receive callbacks when a message is received for the message type
*/
@GuardedBy("mTransports")
- public void addListener(int message, @NonNull Listener listener) {
- mListeners.put(message, listener);
+ public void addListener(int message, @NonNull IOnMessageReceivedListener listener) {
+ mMessageListeners.put(message, listener);
for (int i = 0; i < mTransports.size(); i++) {
mTransports.valueAt(i).addListener(message, listener);
}
}
/**
+ * Add a listener to receive callbacks when any of the transports is changed
+ */
+ @GuardedBy("mTransports")
+ public void addListener(IOnTransportsChangedListener listener) {
+ Slog.i(TAG, "Registering OnTransportsChangedListener");
+ mTransportsListeners.register(listener);
+ List<AssociationInfo> associations = new ArrayList<>();
+ for (int i = 0; i < mTransports.size(); i++) {
+ AssociationInfo association = mAssociationStore.getAssociationById(
+ mTransports.keyAt(i));
+ if (association != null) {
+ associations.add(association);
+ }
+ }
+ mTransportsListeners.broadcast(listener1 -> {
+ // callback to the current listener with all the associations of the transports
+ // immediately
+ if (listener1 == listener) {
+ try {
+ listener.onTransportsChanged(associations);
+ } catch (RemoteException ignored) {
+ }
+ }
+ });
+ }
+
+ /**
+ * Remove the listener for receiving callbacks when any of the transports is changed
+ */
+ public void removeListener(IOnTransportsChangedListener listener) {
+ mTransportsListeners.unregister(listener);
+ }
+
+ /**
+ * Remove the listener to stop receiving calbacks when a message is received for the given type
+ */
+ public void removeListener(int messageType, IOnMessageReceivedListener listener) {
+ mMessageListeners.remove(messageType);
+ }
+
+ /**
+ * Send a message to remote devices through the transports
+ */
+ @GuardedBy("mTransports")
+ public void sendMessage(int message, byte[] data, int[] associationIds) {
+ Slog.i(TAG, "Sending message 0x" + Integer.toHexString(message)
+ + " data length " + data.length);
+ for (int i = 0; i < associationIds.length; i++) {
+ if (mTransports.contains(associationIds[i])) {
+ try {
+ mTransports.get(associationIds[i]).sendMessage(message, data);
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to send message 0x" + Integer.toHexString(message)
+ + " data length " + data.length + " to association "
+ + associationIds[i]);
+ }
+ }
+ }
+ }
+
+ /**
* For the moment, we only offer transporting of system data to built-in
* companion apps; future work will improve the security model to support
* third-party companion apps.
@@ -119,6 +195,8 @@ public class CompanionTransportManager {
}
initializeTransport(associationId, fd);
+
+ notifyOnTransportsChanged();
}
}
@@ -130,16 +208,35 @@ public class CompanionTransportManager {
mTransports.delete(associationId);
transport.stop();
}
+
+ notifyOnTransportsChanged();
}
}
@GuardedBy("mTransports")
+ private void notifyOnTransportsChanged() {
+ List<AssociationInfo> associations = new ArrayList<>();
+ for (int i = 0; i < mTransports.size(); i++) {
+ AssociationInfo association = mAssociationStore.getAssociationById(
+ mTransports.keyAt(i));
+ if (association != null) {
+ associations.add(association);
+ }
+ }
+ mTransportsListeners.broadcast(listener -> {
+ try {
+ listener.onTransportsChanged(associations);
+ } catch (RemoteException ignored) {
+ }
+ });
+ }
+
+ @GuardedBy("mTransports")
private void initializeTransport(int associationId, ParcelFileDescriptor fd) {
+ Slog.i(TAG, "Initializing transport");
if (!isSecureTransportEnabled()) {
Transport transport = new RawTransport(associationId, fd, mContext);
- for (Map.Entry<Integer, Listener> entry : mListeners.entrySet()) {
- transport.addListener(entry.getKey(), entry.getValue());
- }
+ addMessageListenersToTransport(transport);
transport.start();
mTransports.put(associationId, transport);
Slog.i(TAG, "RawTransport is created");
@@ -148,10 +245,21 @@ public class CompanionTransportManager {
// Exchange platform info to decide which transport should be created
mTempTransport = new RawTransport(associationId, fd, mContext);
- for (Map.Entry<Integer, Listener> entry : mListeners.entrySet()) {
- mTempTransport.addListener(entry.getKey(), entry.getValue());
- }
- mTempTransport.addListener(MESSAGE_REQUEST_PLATFORM_INFO, this::onPlatformInfoReceived);
+ addMessageListenersToTransport(mTempTransport);
+ IOnMessageReceivedListener listener = new IOnMessageReceivedListener() {
+ @Override
+ public void onMessageReceived(int associationId, byte[] data) throws RemoteException {
+ synchronized (mTransports) {
+ onPlatformInfoReceived(associationId, data);
+ }
+ }
+
+ @Override
+ public IBinder asBinder() {
+ return null;
+ }
+ };
+ mTempTransport.addListener(MESSAGE_REQUEST_PLATFORM_INFO, listener);
mTempTransport.start();
int sdk = Build.VERSION.SDK_INT;
@@ -163,14 +271,21 @@ public class CompanionTransportManager {
.put(release.getBytes());
// TODO: it should check if preSharedKey is given
- mTempTransport.requestForResponse(MESSAGE_REQUEST_PLATFORM_INFO, data.array());
+ try {
+ mTempTransport.sendMessage(MESSAGE_REQUEST_PLATFORM_INFO, data.array());
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to exchange platform info");
+ }
}
/**
* Depending on the remote platform info to decide which transport should be created
*/
- @GuardedBy("mTransports")
- private void onPlatformInfoReceived(byte[] data) {
+ @GuardedBy("CompanionTransportManager.this.mTransports")
+ private void onPlatformInfoReceived(int associationId, byte[] data) {
+ if (mTempTransport.getAssociationId() != associationId) {
+ return;
+ }
// TODO: it should check if preSharedKey is given
ByteBuffer buffer = ByteBuffer.wrap(data);
@@ -198,12 +313,11 @@ public class CompanionTransportManager {
Slog.i(TAG, "Creating a secure channel");
transport = new SecureTransport(transport.getAssociationId(), transport.getFd(),
mContext);
- for (Map.Entry<Integer, Listener> entry : mListeners.entrySet()) {
- transport.addListener(entry.getKey(), entry.getValue());
- }
+ addMessageListenersToTransport(transport);
transport.start();
}
mTransports.put(transport.getAssociationId(), transport);
+ // Doesn't need to notifyTransportsChanged here, it'll be done in attachSystemDataTransport
}
public Future<?> requestPermissionRestore(int associationId, byte[] data) {
@@ -228,4 +342,10 @@ public class CompanionTransportManager {
return enabled;
}
+
+ private void addMessageListenersToTransport(Transport transport) {
+ for (int i = 0; i < mMessageListeners.size(); i++) {
+ transport.addListener(mMessageListeners.keyAt(i), mMessageListeners.valueAt(i));
+ }
+ }
}
diff --git a/services/companion/java/com/android/server/companion/transport/Transport.java b/services/companion/java/com/android/server/companion/transport/Transport.java
index e984c637b44c..d69ce8909c74 100644
--- a/services/companion/java/com/android/server/companion/transport/Transport.java
+++ b/services/companion/java/com/android/server/companion/transport/Transport.java
@@ -17,10 +17,12 @@
package com.android.server.companion.transport;
import android.annotation.NonNull;
+import android.companion.IOnMessageReceivedListener;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
import android.util.Slog;
import android.util.SparseArray;
@@ -45,7 +47,8 @@ public abstract class Transport {
protected static final boolean DEBUG = Build.IS_DEBUGGABLE;
static final int MESSAGE_REQUEST_PING = 0x63807378; // ?PIN
- public static final int MESSAGE_REQUEST_PLATFORM_INFO = 0x63807086; // ?PFV
+ public static final int MESSAGE_REQUEST_PLATFORM_INFO = 0x63807073; // ?PFI
+ public static final int MESSAGE_REQUEST_CONTEXT_SYNC = 0x63678883; // ?CXS
public static final int MESSAGE_REQUEST_PERMISSION_RESTORE = 0x63826983; // ?RES
static final int MESSAGE_RESPONSE_SUCCESS = 0x33838567; // !SUC
@@ -59,19 +62,14 @@ public abstract class Transport {
protected final OutputStream mRemoteOut;
protected final Context mContext;
- /** Message type -> Listener */
- private final Map<Integer, Listener> mListeners;
-
/**
- * Message listener
+ * Message type -> Listener
+ *
+ * For now, the transport only supports 1 listener for each message type. If there's a need in
+ * the future to allow multiple listeners to receive callbacks for the same message type, the
+ * value of the map can be a list.
*/
- public interface Listener {
- /**
- * Called when a message is received
- * @param data data content in the message
- */
- void onDataReceived(byte[] data);
- }
+ private final Map<Integer, IOnMessageReceivedListener> mListeners;
private static boolean isRequest(int message) {
return (message & 0xFF000000) == 0x63000000;
@@ -100,7 +98,7 @@ public abstract class Transport {
* @param message Message type
* @param listener Execute when a message with the type is received
*/
- public void addListener(int message, Listener listener) {
+ public void addListener(int message, IOnMessageReceivedListener listener) {
mListeners.put(message, listener);
}
@@ -117,6 +115,13 @@ public abstract class Transport {
protected abstract void sendMessage(int message, int sequence, @NonNull byte[] data)
throws IOException;
+ /**
+ * Send a message
+ */
+ public void sendMessage(int message, @NonNull byte[] data) throws IOException {
+ sendMessage(message, mNextSequence.incrementAndGet(), data);
+ }
+
public Future<byte[]> requestForResponse(int message, byte[] data) {
if (DEBUG) Slog.d(TAG, "Requesting for response");
final int sequence = mNextSequence.incrementAndGet();
@@ -165,7 +170,8 @@ public abstract class Transport {
sendMessage(MESSAGE_RESPONSE_SUCCESS, sequence, data);
break;
}
- case MESSAGE_REQUEST_PLATFORM_INFO: {
+ case MESSAGE_REQUEST_PLATFORM_INFO:
+ case MESSAGE_REQUEST_CONTEXT_SYNC: {
callback(message, data);
sendMessage(MESSAGE_RESPONSE_SUCCESS, sequence, EmptyArray.BYTE);
break;
@@ -196,7 +202,13 @@ public abstract class Transport {
private void callback(int message, byte[] data) {
if (mListeners.containsKey(message)) {
- mListeners.get(message).onDataReceived(data);
+ try {
+ mListeners.get(message).onMessageReceived(getAssociationId(), data);
+ Slog.i(TAG, "Message 0x" + Integer.toHexString(message)
+ + " is received from associationId " + mAssociationId
+ + ", sending data length " + data.length + " to the listener.");
+ } catch (RemoteException ignored) {
+ }
}
}