Merge "Revert "[CDM Transport] Exchange platform info to decide which Transport to"" into udc-dev am: 8186b7edc8

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/21661331

Change-Id: Icb9a270ba798f7cbb9aa43410af17c7c179da747
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Cole Faust
2023-03-01 05:57:20 +00:00
committed by Automerger Merge Worker
8 changed files with 116 additions and 214 deletions

View File

@@ -23,7 +23,6 @@ import static android.companion.CompanionDeviceManager.COMPANION_DEVICE_DISCOVER
import static android.content.ComponentName.createRelative; import static android.content.ComponentName.createRelative;
import static com.android.server.companion.Utils.prepareForIpc; import static com.android.server.companion.Utils.prepareForIpc;
import static com.android.server.companion.transport.Transport.MESSAGE_REQUEST_PERMISSION_RESTORE;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
@@ -92,8 +91,7 @@ public class SystemDataTransferProcessor {
mAssociationStore = associationStore; mAssociationStore = associationStore;
mSystemDataTransferRequestStore = systemDataTransferRequestStore; mSystemDataTransferRequestStore = systemDataTransferRequestStore;
mTransportManager = transportManager; mTransportManager = transportManager;
mTransportManager.addListener(MESSAGE_REQUEST_PERMISSION_RESTORE, mTransportManager.setListener(this::onReceivePermissionRestore);
this::onReceivePermissionRestore);
mPermissionControllerManager = mContext.getSystemService(PermissionControllerManager.class); mPermissionControllerManager = mContext.getSystemService(PermissionControllerManager.class);
mExecutor = Executors.newSingleThreadExecutor(); mExecutor = Executors.newSingleThreadExecutor();
} }

View File

@@ -35,7 +35,7 @@ import java.util.function.BiConsumer;
/** /**
* Helper class to perform attestation verification synchronously. * Helper class to perform attestation verification synchronously.
*/ */
public class AttestationVerifier { class AttestationVerifier {
private static final long ATTESTATION_VERIFICATION_TIMEOUT_SECONDS = 10; // 10 seconds private static final long ATTESTATION_VERIFICATION_TIMEOUT_SECONDS = 10; // 10 seconds
private static final String PARAM_OWNED_BY_SYSTEM = "android.key_owned_by_system"; private static final String PARAM_OWNED_BY_SYSTEM = "android.key_owned_by_system";

View File

@@ -110,7 +110,7 @@ public class SecureChannel {
this(in, out, callback, null, new AttestationVerifier(context)); this(in, out, callback, null, new AttestationVerifier(context));
} }
public SecureChannel( private SecureChannel(
final InputStream in, final InputStream in,
final OutputStream out, final OutputStream out,
Callback callback, Callback callback,
@@ -381,10 +381,9 @@ public class SecureChannel {
private void exchangeAuthentication() private void exchangeAuthentication()
throws IOException, GeneralSecurityException, BadHandleException, CryptoException { throws IOException, GeneralSecurityException, BadHandleException, CryptoException {
if (mPreSharedKey != null) { if (mVerifier == null) {
exchangePreSharedKey(); exchangePreSharedKey();
} } else {
if (mVerifier != null) {
exchangeAttestation(); exchangeAttestation();
} }
} }

View File

@@ -19,9 +19,9 @@ package com.android.server.companion.transport;
import static android.Manifest.permission.DELIVER_COMPANION_MESSAGES; import static android.Manifest.permission.DELIVER_COMPANION_MESSAGES;
import static com.android.server.companion.transport.Transport.MESSAGE_REQUEST_PERMISSION_RESTORE; import static com.android.server.companion.transport.Transport.MESSAGE_REQUEST_PERMISSION_RESTORE;
import static com.android.server.companion.transport.Transport.MESSAGE_REQUEST_PLATFORM_INFO;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.ActivityManagerInternal; import android.app.ActivityManagerInternal;
import android.content.Context; import android.content.Context;
@@ -30,17 +30,12 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Binder; import android.os.Binder;
import android.os.Build; import android.os.Build;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
import android.util.Slog;
import android.util.SparseArray; import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy;
import com.android.server.LocalServices; import com.android.server.LocalServices;
import com.android.server.companion.transport.Transport.Listener;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future; import java.util.concurrent.Future;
@@ -49,8 +44,6 @@ public class CompanionTransportManager {
private static final String TAG = "CDM_CompanionTransportManager"; private static final String TAG = "CDM_CompanionTransportManager";
private static final boolean DEBUG = false; private static final boolean DEBUG = false;
private static final int NON_ANDROID = -1;
private boolean mSecureTransportEnabled = true; private boolean mSecureTransportEnabled = true;
private static boolean isRequest(int message) { private static boolean isRequest(int message) {
@@ -61,29 +54,24 @@ public class CompanionTransportManager {
return (message & 0xFF000000) == 0x33000000; return (message & 0xFF000000) == 0x33000000;
} }
public interface Listener {
void onRequestPermissionRestore(byte[] data);
}
private final Context mContext; private final Context mContext;
@GuardedBy("mTransports") @GuardedBy("mTransports")
private final SparseArray<Transport> mTransports = new SparseArray<>(); private final SparseArray<Transport> mTransports = new SparseArray<>();
@NonNull @Nullable
private final Map<Integer, Listener> mListeners = new HashMap<>(); private Listener mListener;
private Transport mTempTransport;
public CompanionTransportManager(Context context) { public CompanionTransportManager(Context context) {
mContext = context; mContext = context;
} }
/** public void setListener(@NonNull Listener listener) {
* Add a message listener when a message is received for the message type mListener = listener;
*/
@GuardedBy("mTransports")
public void addListener(int message, @NonNull Listener listener) {
mListeners.put(message, listener);
for (int i = 0; i < mTransports.size(); i++) {
mTransports.valueAt(i).addListener(message, listener);
}
} }
/** /**
@@ -117,7 +105,15 @@ public class CompanionTransportManager {
detachSystemDataTransport(packageName, userId, associationId); detachSystemDataTransport(packageName, userId, associationId);
} }
initializeTransport(associationId, fd); final Transport transport;
if (isSecureTransportEnabled(associationId)) {
transport = new SecureTransport(associationId, fd, mContext, mListener);
} else {
transport = new RawTransport(associationId, fd, mContext, mListener);
}
transport.start();
mTransports.put(associationId, transport);
} }
} }
@@ -132,85 +128,13 @@ public class CompanionTransportManager {
} }
} }
@GuardedBy("mTransports")
private void initializeTransport(int associationId, ParcelFileDescriptor fd) {
if (!isSecureTransportEnabled()) {
Transport transport = new RawTransport(associationId, fd, mContext);
for (Map.Entry<Integer, Listener> entry : mListeners.entrySet()) {
transport.addListener(entry.getKey(), entry.getValue());
}
transport.start();
mTransports.put(associationId, transport);
Slog.i(TAG, "RawTransport is created");
return;
}
// 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);
mTempTransport.start();
int sdk = Build.VERSION.SDK_INT;
String release = Build.VERSION.RELEASE;
// data format: | SDK_INT (int) | release length (int) | release |
final ByteBuffer data = ByteBuffer.allocate(4 + 4 + release.getBytes().length)
.putInt(sdk)
.putInt(release.getBytes().length)
.put(release.getBytes());
// TODO: it should check if preSharedKey is given
mTempTransport.requestForResponse(MESSAGE_REQUEST_PLATFORM_INFO, data.array());
}
/**
* Depending on the remote platform info to decide which transport should be created
*/
@GuardedBy("mTransports")
private void onPlatformInfoReceived(byte[] data) {
// TODO: it should check if preSharedKey is given
ByteBuffer buffer = ByteBuffer.wrap(data);
int remoteSdk = buffer.getInt();
byte[] remoteRelease = new byte[buffer.getInt()];
buffer.get(remoteRelease);
Slog.i(TAG, "Remote device SDK: " + remoteSdk + ", release:" + new String(remoteRelease));
Transport transport = mTempTransport;
mTempTransport = null;
int sdk = Build.VERSION.SDK_INT;
String release = Build.VERSION.RELEASE;
if (remoteSdk == NON_ANDROID) {
// TODO: pass in a real preSharedKey
transport = new SecureTransport(transport.getAssociationId(), transport.getFd(),
mContext, null, null);
} else if (sdk < Build.VERSION_CODES.UPSIDE_DOWN_CAKE
|| remoteSdk < Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
// TODO: depending on the release version, either
// 1) using a RawTransport for old T versions
// 2) or an Ukey2 handshaked transport for UKey2 backported T versions
} else {
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());
}
transport.start();
}
mTransports.put(transport.getAssociationId(), transport);
}
public Future<?> requestPermissionRestore(int associationId, byte[] data) { public Future<?> requestPermissionRestore(int associationId, byte[] data) {
synchronized (mTransports) { synchronized (mTransports) {
final Transport transport = mTransports.get(associationId); final Transport transport = mTransports.get(associationId);
if (transport == null) { if (transport == null) {
return CompletableFuture.failedFuture(new IOException("Missing transport")); return CompletableFuture.failedFuture(new IOException("Missing transport"));
} }
return transport.requestForResponse(MESSAGE_REQUEST_PERMISSION_RESTORE, data); return transport.requestForResponse(MESSAGE_REQUEST_PERMISSION_RESTORE, data);
} }
} }
@@ -222,9 +146,10 @@ public class CompanionTransportManager {
this.mSecureTransportEnabled = enabled; this.mSecureTransportEnabled = enabled;
} }
private boolean isSecureTransportEnabled() { private boolean isSecureTransportEnabled(int associationId) {
boolean enabled = !Build.IS_DEBUGGABLE || mSecureTransportEnabled; boolean enabled = !Build.IS_DEBUGGABLE || mSecureTransportEnabled;
// TODO: version comparison logic
return enabled; return enabled;
} }
} }

View File

@@ -16,51 +16,51 @@
package com.android.server.companion.transport; package com.android.server.companion.transport;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import android.util.Slog; import android.util.Slog;
import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.security.InvalidAlgorithmParameterException; import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.Arrays; import java.security.UnrecoverableEntryException;
import java.security.cert.CertificateException;
import javax.crypto.BadPaddingException; import javax.crypto.BadPaddingException;
import javax.crypto.Cipher; import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException; import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException; import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
/** /**
* This class uses Java Cryptography to encrypt and decrypt messages * This class can be used to encrypt and decrypt bytes using Android Cryptography
*/ */
public class CryptoManager { public class CryptoManager {
private static final String TAG = "CDM_CryptoManager"; private static final String TAG = "CDM_CryptoManager";
private static final int SECRET_KEY_LENGTH = 32;
private static final String ALGORITHM = "AES";
private static final String TRANSFORMATION = "AES/CBC/PKCS7Padding";
private final byte[] mPreSharedKey; private static final String KEY_STORE_ALIAS = "cdm_secret";
private Cipher mEncryptCipher; private static final String ALGORITHM = KeyProperties.KEY_ALGORITHM_AES;
private Cipher mDecryptCipher; private static final String BLOCK_MODE = KeyProperties.BLOCK_MODE_CBC;
private static final String PADDING = KeyProperties.ENCRYPTION_PADDING_PKCS7;
private static final String TRANSFORMATION = ALGORITHM + "/" + BLOCK_MODE + "/" + PADDING;
private SecretKey mSecretKey; private final KeyStore mKeyStore;
public CryptoManager(byte[] preSharedKey) { public CryptoManager() {
if (preSharedKey == null) { // Initialize KeyStore
mPreSharedKey = Arrays.copyOf(new byte[0], SECRET_KEY_LENGTH);
} else {
mPreSharedKey = Arrays.copyOf(preSharedKey, SECRET_KEY_LENGTH);
}
mSecretKey = new SecretKeySpec(mPreSharedKey, ALGORITHM);
try { try {
mEncryptCipher = Cipher.getInstance(TRANSFORMATION); mKeyStore = KeyStore.getInstance("AndroidKeyStore");
mEncryptCipher.init(Cipher.ENCRYPT_MODE, mSecretKey); mKeyStore.load(null);
mDecryptCipher = Cipher.getInstance(TRANSFORMATION); } catch (KeyStoreException | IOException | NoSuchAlgorithmException
} catch (NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException e) { | CertificateException e) {
Slog.e(TAG, e.getMessage()); throw new RuntimeException(e);
} }
} }
@@ -69,19 +69,21 @@ public class CryptoManager {
*/ */
public byte[] encrypt(byte[] input) { public byte[] encrypt(byte[] input) {
try { try {
if (mEncryptCipher == null) { // Encrypt using Cipher
return null; Cipher encryptCipher = Cipher.getInstance(TRANSFORMATION);
} encryptCipher.init(Cipher.ENCRYPT_MODE, getKey());
byte[] encryptedBytes = encryptCipher.doFinal(input);
byte[] encryptedBytes = mEncryptCipher.doFinal(input); // Write to bytes
ByteBuffer buffer = ByteBuffer.allocate( ByteBuffer buffer = ByteBuffer.allocate(
4 + mEncryptCipher.getIV().length + 4 + encryptedBytes.length) 4 + encryptCipher.getIV().length + 4 + encryptedBytes.length)
.putInt(mEncryptCipher.getIV().length) .putInt(encryptCipher.getIV().length)
.put(mEncryptCipher.getIV()) .put(encryptCipher.getIV())
.putInt(encryptedBytes.length) .putInt(encryptedBytes.length)
.put(encryptedBytes); .put(encryptedBytes);
return buffer.array(); return buffer.array();
} catch (IllegalBlockSizeException | BadPaddingException e) { } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException
| IllegalBlockSizeException | BadPaddingException e) {
Slog.e(TAG, e.getMessage()); Slog.e(TAG, e.getMessage());
return null; return null;
} }
@@ -97,20 +99,45 @@ public class CryptoManager {
byte[] encryptedBytes = new byte[buffer.getInt()]; byte[] encryptedBytes = new byte[buffer.getInt()];
buffer.get(encryptedBytes); buffer.get(encryptedBytes);
try { try {
mDecryptCipher.init(Cipher.DECRYPT_MODE, getKey(), new IvParameterSpec(iv)); Cipher decryptCipher = Cipher.getInstance(TRANSFORMATION);
return mDecryptCipher.doFinal(encryptedBytes); decryptCipher.init(Cipher.DECRYPT_MODE, getKey(), new IvParameterSpec(iv));
} catch (InvalidKeyException | InvalidAlgorithmParameterException return decryptCipher.doFinal(encryptedBytes);
| IllegalBlockSizeException | BadPaddingException e) { } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException
| InvalidAlgorithmParameterException | IllegalBlockSizeException
| BadPaddingException e) {
Slog.e(TAG, e.getMessage()); Slog.e(TAG, e.getMessage());
return null; return null;
} }
} }
private SecretKey getKey() { private SecretKey getKey() {
if (mSecretKey != null) { try {
return mSecretKey; KeyStore.Entry keyEntry = mKeyStore.getEntry(KEY_STORE_ALIAS, null);
if (keyEntry instanceof KeyStore.SecretKeyEntry
&& ((KeyStore.SecretKeyEntry) keyEntry).getSecretKey() != null) {
return ((KeyStore.SecretKeyEntry) keyEntry).getSecretKey();
} else {
return createKey();
}
} catch (NoSuchAlgorithmException | UnrecoverableEntryException | KeyStoreException e) {
throw new RuntimeException(e);
}
}
private SecretKey createKey() {
try {
KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM);
keyGenerator.init(
new KeyGenParameterSpec.Builder(KEY_STORE_ALIAS,
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(BLOCK_MODE)
.setEncryptionPaddings(PADDING)
.setUserAuthenticationRequired(false)
.setRandomizedEncryptionRequired(true)
.build());
return keyGenerator.generateKey();
} catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException e) {
throw new RuntimeException(e);
} }
mSecretKey = new SecretKeySpec(mPreSharedKey, ALGORITHM);
return mSecretKey;
} }
} }

View File

@@ -21,6 +21,8 @@ import android.content.Context;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
import android.util.Slog; import android.util.Slog;
import com.android.server.companion.transport.CompanionTransportManager.Listener;
import libcore.io.IoUtils; import libcore.io.IoUtils;
import libcore.io.Streams; import libcore.io.Streams;
@@ -30,8 +32,8 @@ import java.nio.ByteBuffer;
class RawTransport extends Transport { class RawTransport extends Transport {
private volatile boolean mStopped; private volatile boolean mStopped;
RawTransport(int associationId, ParcelFileDescriptor fd, Context context) { RawTransport(int associationId, ParcelFileDescriptor fd, Context context, Listener listener) {
super(associationId, fd, context); super(associationId, fd, context, listener);
} }
@Override @Override
@@ -62,7 +64,7 @@ class RawTransport extends Transport {
protected void sendMessage(int message, int sequence, @NonNull byte[] data) protected void sendMessage(int message, int sequence, @NonNull byte[] data)
throws IOException { throws IOException {
if (DEBUG) { if (DEBUG) {
Slog.e(TAG, "Sending message 0x" + Integer.toHexString(message) Slog.d(TAG, "Sending message 0x" + Integer.toHexString(message)
+ " sequence " + sequence + " length " + data.length + " sequence " + sequence + " length " + data.length
+ " to association " + mAssociationId); + " to association " + mAssociationId);
} }

View File

@@ -21,8 +21,8 @@ import android.content.Context;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
import android.util.Slog; import android.util.Slog;
import com.android.server.companion.securechannel.AttestationVerifier;
import com.android.server.companion.securechannel.SecureChannel; import com.android.server.companion.securechannel.SecureChannel;
import com.android.server.companion.transport.CompanionTransportManager.Listener;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@@ -37,17 +37,14 @@ class SecureTransport extends Transport implements SecureChannel.Callback {
private final BlockingQueue<byte[]> mRequestQueue = new ArrayBlockingQueue<>(100); private final BlockingQueue<byte[]> mRequestQueue = new ArrayBlockingQueue<>(100);
SecureTransport(int associationId, ParcelFileDescriptor fd, Context context) { SecureTransport(int associationId,
super(associationId, fd, context); ParcelFileDescriptor fd,
Context context,
Listener listener) {
super(associationId, fd, context, listener);
mSecureChannel = new SecureChannel(mRemoteIn, mRemoteOut, this, context); mSecureChannel = new SecureChannel(mRemoteIn, mRemoteOut, this, context);
} }
SecureTransport(int associationId, ParcelFileDescriptor fd, Context context,
byte[] preSharedKey, AttestationVerifier verifier) {
super(associationId, fd, context);
mSecureChannel = new SecureChannel(mRemoteIn, mRemoteOut, this, preSharedKey, verifier);
}
@Override @Override
public void start() { public void start() {
mSecureChannel.start(); mSecureChannel.start();

View File

@@ -25,28 +25,23 @@ import android.util.Slog;
import android.util.SparseArray; import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy;
import com.android.server.companion.transport.CompanionTransportManager.Listener;
import libcore.util.EmptyArray; import libcore.util.EmptyArray;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
/** abstract class Transport {
* This class represents the channel established between two devices.
*/
public abstract class Transport {
protected static final String TAG = "CDM_CompanionTransport"; protected static final String TAG = "CDM_CompanionTransport";
protected static final boolean DEBUG = Build.IS_DEBUGGABLE; protected static final boolean DEBUG = Build.IS_DEBUGGABLE;
static final int MESSAGE_REQUEST_PING = 0x63807378; // ?PIN static final int MESSAGE_REQUEST_PING = 0x63807378; // ?PIN
public static final int MESSAGE_REQUEST_PLATFORM_INFO = 0x63807086; // ?PFV static final int MESSAGE_REQUEST_PERMISSION_RESTORE = 0x63826983; // ?RES
public static final int MESSAGE_REQUEST_PERMISSION_RESTORE = 0x63826983; // ?RES
static final int MESSAGE_RESPONSE_SUCCESS = 0x33838567; // !SUC static final int MESSAGE_RESPONSE_SUCCESS = 0x33838567; // !SUC
static final int MESSAGE_RESPONSE_FAILURE = 0x33706573; // !FAI static final int MESSAGE_RESPONSE_FAILURE = 0x33706573; // !FAI
@@ -54,24 +49,11 @@ public abstract class Transport {
protected static final int HEADER_LENGTH = 12; protected static final int HEADER_LENGTH = 12;
protected final int mAssociationId; protected final int mAssociationId;
protected final ParcelFileDescriptor mFd;
protected final InputStream mRemoteIn; protected final InputStream mRemoteIn;
protected final OutputStream mRemoteOut; protected final OutputStream mRemoteOut;
protected final Context mContext; protected final Context mContext;
/** Message type -> Listener */ private final Listener mListener;
private final Map<Integer, Listener> mListeners;
/**
* Message listener
*/
public interface Listener {
/**
* Called when a message is received
* @param data data content in the message
*/
void onDataReceived(byte[] data);
}
private static boolean isRequest(int message) { private static boolean isRequest(int message) {
return (message & 0xFF000000) == 0x63000000; return (message & 0xFF000000) == 0x63000000;
@@ -86,36 +68,16 @@ public abstract class Transport {
new SparseArray<>(); new SparseArray<>();
protected final AtomicInteger mNextSequence = new AtomicInteger(); protected final AtomicInteger mNextSequence = new AtomicInteger();
Transport(int associationId, ParcelFileDescriptor fd, Context context) { Transport(int associationId, ParcelFileDescriptor fd, Context context, Listener listener) {
mAssociationId = associationId; this.mAssociationId = associationId;
mFd = fd; this.mRemoteIn = new ParcelFileDescriptor.AutoCloseInputStream(fd);
mRemoteIn = new ParcelFileDescriptor.AutoCloseInputStream(fd); this.mRemoteOut = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
mRemoteOut = new ParcelFileDescriptor.AutoCloseOutputStream(fd); this.mContext = context;
mContext = context; this.mListener = listener;
mListeners = new HashMap<>();
}
/**
* Add a listener when a message is received for the message type
* @param message Message type
* @param listener Execute when a message with the type is received
*/
public void addListener(int message, Listener listener) {
mListeners.put(message, listener);
}
public int getAssociationId() {
return mAssociationId;
}
protected ParcelFileDescriptor getFd() {
return mFd;
} }
public abstract void start(); public abstract void start();
public abstract void stop(); public abstract void stop();
protected abstract void sendMessage(int message, int sequence, @NonNull byte[] data)
throws IOException;
public Future<byte[]> requestForResponse(int message, byte[] data) { public Future<byte[]> requestForResponse(int message, byte[] data) {
if (DEBUG) Slog.d(TAG, "Requesting for response"); if (DEBUG) Slog.d(TAG, "Requesting for response");
@@ -137,6 +99,9 @@ public abstract class Transport {
return pending; return pending;
} }
protected abstract void sendMessage(int message, int sequence, @NonNull byte[] data)
throws IOException;
protected final void handleMessage(int message, int sequence, @NonNull byte[] data) protected final void handleMessage(int message, int sequence, @NonNull byte[] data)
throws IOException { throws IOException {
if (DEBUG) { if (DEBUG) {
@@ -165,11 +130,6 @@ public abstract class Transport {
sendMessage(MESSAGE_RESPONSE_SUCCESS, sequence, data); sendMessage(MESSAGE_RESPONSE_SUCCESS, sequence, data);
break; break;
} }
case MESSAGE_REQUEST_PLATFORM_INFO: {
callback(message, data);
sendMessage(MESSAGE_RESPONSE_SUCCESS, sequence, EmptyArray.BYTE);
break;
}
case MESSAGE_REQUEST_PERMISSION_RESTORE: { case MESSAGE_REQUEST_PERMISSION_RESTORE: {
if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH) if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)
&& !Build.isDebuggable()) { && !Build.isDebuggable()) {
@@ -178,7 +138,7 @@ public abstract class Transport {
break; break;
} }
try { try {
callback(message, data); mListener.onRequestPermissionRestore(data);
sendMessage(MESSAGE_RESPONSE_SUCCESS, sequence, EmptyArray.BYTE); sendMessage(MESSAGE_RESPONSE_SUCCESS, sequence, EmptyArray.BYTE);
} catch (Exception e) { } catch (Exception e) {
Slog.w(TAG, "Failed to restore permissions"); Slog.w(TAG, "Failed to restore permissions");
@@ -194,12 +154,6 @@ public abstract class Transport {
} }
} }
private void callback(int message, byte[] data) {
if (mListeners.containsKey(message)) {
mListeners.get(message).onDataReceived(data);
}
}
private void processResponse(int message, int sequence, byte[] data) { private void processResponse(int message, int sequence, byte[] data) {
final CompletableFuture<byte[]> future; final CompletableFuture<byte[]> future;
synchronized (mPendingRequests) { synchronized (mPendingRequests) {