[CDM ContextSync] ContextSync support APIs
Allow ContextSync to listen to transport changes, send & receive messages Bug: 253307662 Test: m build Change-Id: I424ca4ae8f1578328e093733a0f06b621aca7a07
This commit is contained in:
@@ -800,6 +800,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
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
23
core/java/android/companion/IOnMessageReceivedListener.aidl
Normal file
23
core/java/android/companion/IOnMessageReceivedListener.aidl
Normal file
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -600,6 +602,37 @@ public class CompanionDeviceManagerService extends SystemService {
|
||||
mListeners.unregister(listener);
|
||||
}
|
||||
|
||||
@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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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,30 +70,99 @@ 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
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user