Revert "[CDM Transport] Exchange platform info to decide which Transport to"
This reverts commit 66495b5800.
Reason for revert: Breaks errorprone build
Change-Id: Id39c25422eb66c88283fe98ab99dec51735e58ed
This commit is contained in:
committed by
Android (Google) Code Review
parent
66495b5800
commit
448bfa20b7
@@ -23,7 +23,6 @@ import static android.companion.CompanionDeviceManager.COMPANION_DEVICE_DISCOVER
|
||||
import static android.content.ComponentName.createRelative;
|
||||
|
||||
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.Nullable;
|
||||
@@ -92,8 +91,7 @@ public class SystemDataTransferProcessor {
|
||||
mAssociationStore = associationStore;
|
||||
mSystemDataTransferRequestStore = systemDataTransferRequestStore;
|
||||
mTransportManager = transportManager;
|
||||
mTransportManager.addListener(MESSAGE_REQUEST_PERMISSION_RESTORE,
|
||||
this::onReceivePermissionRestore);
|
||||
mTransportManager.setListener(this::onReceivePermissionRestore);
|
||||
mPermissionControllerManager = mContext.getSystemService(PermissionControllerManager.class);
|
||||
mExecutor = Executors.newSingleThreadExecutor();
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ import java.util.function.BiConsumer;
|
||||
/**
|
||||
* 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 String PARAM_OWNED_BY_SYSTEM = "android.key_owned_by_system";
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ public class SecureChannel {
|
||||
this(in, out, callback, null, new AttestationVerifier(context));
|
||||
}
|
||||
|
||||
public SecureChannel(
|
||||
private SecureChannel(
|
||||
final InputStream in,
|
||||
final OutputStream out,
|
||||
Callback callback,
|
||||
@@ -381,10 +381,9 @@ public class SecureChannel {
|
||||
|
||||
private void exchangeAuthentication()
|
||||
throws IOException, GeneralSecurityException, BadHandleException, CryptoException {
|
||||
if (mPreSharedKey != null) {
|
||||
if (mVerifier == null) {
|
||||
exchangePreSharedKey();
|
||||
}
|
||||
if (mVerifier != null) {
|
||||
} else {
|
||||
exchangeAttestation();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,9 +19,9 @@ package com.android.server.companion.transport;
|
||||
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_PLATFORM_INFO;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.ActivityManagerInternal;
|
||||
import android.content.Context;
|
||||
@@ -30,17 +30,12 @@ import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.os.Binder;
|
||||
import android.os.Build;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
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 java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
@@ -49,8 +44,6 @@ public class CompanionTransportManager {
|
||||
private static final String TAG = "CDM_CompanionTransportManager";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private static final int NON_ANDROID = -1;
|
||||
|
||||
private boolean mSecureTransportEnabled = true;
|
||||
|
||||
private static boolean isRequest(int message) {
|
||||
@@ -61,29 +54,24 @@ public class CompanionTransportManager {
|
||||
return (message & 0xFF000000) == 0x33000000;
|
||||
}
|
||||
|
||||
public interface Listener {
|
||||
void onRequestPermissionRestore(byte[] data);
|
||||
}
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
@GuardedBy("mTransports")
|
||||
private final SparseArray<Transport> mTransports = new SparseArray<>();
|
||||
|
||||
@NonNull
|
||||
private final Map<Integer, Listener> mListeners = new HashMap<>();
|
||||
|
||||
private Transport mTempTransport;
|
||||
@Nullable
|
||||
private Listener mListener;
|
||||
|
||||
public CompanionTransportManager(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a message listener when a message is received for the message type
|
||||
*/
|
||||
@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);
|
||||
}
|
||||
public void setListener(@NonNull Listener listener) {
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -117,7 +105,15 @@ public class CompanionTransportManager {
|
||||
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) {
|
||||
synchronized (mTransports) {
|
||||
final Transport transport = mTransports.get(associationId);
|
||||
if (transport == null) {
|
||||
return CompletableFuture.failedFuture(new IOException("Missing transport"));
|
||||
}
|
||||
|
||||
return transport.requestForResponse(MESSAGE_REQUEST_PERMISSION_RESTORE, data);
|
||||
}
|
||||
}
|
||||
@@ -222,9 +146,10 @@ public class CompanionTransportManager {
|
||||
this.mSecureTransportEnabled = enabled;
|
||||
}
|
||||
|
||||
private boolean isSecureTransportEnabled() {
|
||||
private boolean isSecureTransportEnabled(int associationId) {
|
||||
boolean enabled = !Build.IS_DEBUGGABLE || mSecureTransportEnabled;
|
||||
|
||||
// TODO: version comparison logic
|
||||
return enabled;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,51 +16,51 @@
|
||||
|
||||
package com.android.server.companion.transport;
|
||||
|
||||
import android.security.keystore.KeyGenParameterSpec;
|
||||
import android.security.keystore.KeyProperties;
|
||||
import android.util.Slog;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
import java.security.UnrecoverableEntryException;
|
||||
import java.security.cert.CertificateException;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.KeyGenerator;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.SecretKey;
|
||||
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 {
|
||||
|
||||
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 Cipher mEncryptCipher;
|
||||
private Cipher mDecryptCipher;
|
||||
private static final String KEY_STORE_ALIAS = "cdm_secret";
|
||||
private static final String ALGORITHM = KeyProperties.KEY_ALGORITHM_AES;
|
||||
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) {
|
||||
if (preSharedKey == null) {
|
||||
mPreSharedKey = Arrays.copyOf(new byte[0], SECRET_KEY_LENGTH);
|
||||
} else {
|
||||
mPreSharedKey = Arrays.copyOf(preSharedKey, SECRET_KEY_LENGTH);
|
||||
}
|
||||
mSecretKey = new SecretKeySpec(mPreSharedKey, ALGORITHM);
|
||||
public CryptoManager() {
|
||||
// Initialize KeyStore
|
||||
try {
|
||||
mEncryptCipher = Cipher.getInstance(TRANSFORMATION);
|
||||
mEncryptCipher.init(Cipher.ENCRYPT_MODE, mSecretKey);
|
||||
mDecryptCipher = Cipher.getInstance(TRANSFORMATION);
|
||||
} catch (NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException e) {
|
||||
Slog.e(TAG, e.getMessage());
|
||||
mKeyStore = KeyStore.getInstance("AndroidKeyStore");
|
||||
mKeyStore.load(null);
|
||||
} catch (KeyStoreException | IOException | NoSuchAlgorithmException
|
||||
| CertificateException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,19 +69,21 @@ public class CryptoManager {
|
||||
*/
|
||||
public byte[] encrypt(byte[] input) {
|
||||
try {
|
||||
if (mEncryptCipher == null) {
|
||||
return null;
|
||||
}
|
||||
// Encrypt using Cipher
|
||||
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(
|
||||
4 + mEncryptCipher.getIV().length + 4 + encryptedBytes.length)
|
||||
.putInt(mEncryptCipher.getIV().length)
|
||||
.put(mEncryptCipher.getIV())
|
||||
4 + encryptCipher.getIV().length + 4 + encryptedBytes.length)
|
||||
.putInt(encryptCipher.getIV().length)
|
||||
.put(encryptCipher.getIV())
|
||||
.putInt(encryptedBytes.length)
|
||||
.put(encryptedBytes);
|
||||
return buffer.array();
|
||||
} catch (IllegalBlockSizeException | BadPaddingException e) {
|
||||
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException
|
||||
| IllegalBlockSizeException | BadPaddingException e) {
|
||||
Slog.e(TAG, e.getMessage());
|
||||
return null;
|
||||
}
|
||||
@@ -97,20 +99,45 @@ public class CryptoManager {
|
||||
byte[] encryptedBytes = new byte[buffer.getInt()];
|
||||
buffer.get(encryptedBytes);
|
||||
try {
|
||||
mDecryptCipher.init(Cipher.DECRYPT_MODE, getKey(), new IvParameterSpec(iv));
|
||||
return mDecryptCipher.doFinal(encryptedBytes);
|
||||
} catch (InvalidKeyException | InvalidAlgorithmParameterException
|
||||
| IllegalBlockSizeException | BadPaddingException e) {
|
||||
Cipher decryptCipher = Cipher.getInstance(TRANSFORMATION);
|
||||
decryptCipher.init(Cipher.DECRYPT_MODE, getKey(), new IvParameterSpec(iv));
|
||||
return decryptCipher.doFinal(encryptedBytes);
|
||||
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException
|
||||
| InvalidAlgorithmParameterException | IllegalBlockSizeException
|
||||
| BadPaddingException e) {
|
||||
Slog.e(TAG, e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private SecretKey getKey() {
|
||||
if (mSecretKey != null) {
|
||||
return mSecretKey;
|
||||
try {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@ import android.content.Context;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.server.companion.transport.CompanionTransportManager.Listener;
|
||||
|
||||
import libcore.io.IoUtils;
|
||||
import libcore.io.Streams;
|
||||
|
||||
@@ -30,8 +32,8 @@ import java.nio.ByteBuffer;
|
||||
class RawTransport extends Transport {
|
||||
private volatile boolean mStopped;
|
||||
|
||||
RawTransport(int associationId, ParcelFileDescriptor fd, Context context) {
|
||||
super(associationId, fd, context);
|
||||
RawTransport(int associationId, ParcelFileDescriptor fd, Context context, Listener listener) {
|
||||
super(associationId, fd, context, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -62,7 +64,7 @@ class RawTransport extends Transport {
|
||||
protected void sendMessage(int message, int sequence, @NonNull byte[] data)
|
||||
throws IOException {
|
||||
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
|
||||
+ " to association " + mAssociationId);
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@ import android.content.Context;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.server.companion.securechannel.AttestationVerifier;
|
||||
import com.android.server.companion.securechannel.SecureChannel;
|
||||
import com.android.server.companion.transport.CompanionTransportManager.Listener;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
@@ -37,17 +37,14 @@ class SecureTransport extends Transport implements SecureChannel.Callback {
|
||||
|
||||
private final BlockingQueue<byte[]> mRequestQueue = new ArrayBlockingQueue<>(100);
|
||||
|
||||
SecureTransport(int associationId, ParcelFileDescriptor fd, Context context) {
|
||||
super(associationId, fd, context);
|
||||
SecureTransport(int associationId,
|
||||
ParcelFileDescriptor fd,
|
||||
Context context,
|
||||
Listener listener) {
|
||||
super(associationId, fd, context, listener);
|
||||
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
|
||||
public void start() {
|
||||
mSecureChannel.start();
|
||||
|
||||
@@ -25,28 +25,23 @@ import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.server.companion.transport.CompanionTransportManager.Listener;
|
||||
|
||||
import libcore.util.EmptyArray;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* This class represents the channel established between two devices.
|
||||
*/
|
||||
public abstract class Transport {
|
||||
abstract class Transport {
|
||||
protected static final String TAG = "CDM_CompanionTransport";
|
||||
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_PERMISSION_RESTORE = 0x63826983; // ?RES
|
||||
static final int MESSAGE_REQUEST_PERMISSION_RESTORE = 0x63826983; // ?RES
|
||||
|
||||
static final int MESSAGE_RESPONSE_SUCCESS = 0x33838567; // !SUC
|
||||
static final int MESSAGE_RESPONSE_FAILURE = 0x33706573; // !FAI
|
||||
@@ -54,24 +49,11 @@ public abstract class Transport {
|
||||
protected static final int HEADER_LENGTH = 12;
|
||||
|
||||
protected final int mAssociationId;
|
||||
protected final ParcelFileDescriptor mFd;
|
||||
protected final InputStream mRemoteIn;
|
||||
protected final OutputStream mRemoteOut;
|
||||
protected final Context mContext;
|
||||
|
||||
/** Message type -> Listener */
|
||||
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 final Listener mListener;
|
||||
|
||||
private static boolean isRequest(int message) {
|
||||
return (message & 0xFF000000) == 0x63000000;
|
||||
@@ -86,36 +68,16 @@ public abstract class Transport {
|
||||
new SparseArray<>();
|
||||
protected final AtomicInteger mNextSequence = new AtomicInteger();
|
||||
|
||||
Transport(int associationId, ParcelFileDescriptor fd, Context context) {
|
||||
mAssociationId = associationId;
|
||||
mFd = fd;
|
||||
mRemoteIn = new ParcelFileDescriptor.AutoCloseInputStream(fd);
|
||||
mRemoteOut = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
|
||||
mContext = context;
|
||||
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;
|
||||
Transport(int associationId, ParcelFileDescriptor fd, Context context, Listener listener) {
|
||||
this.mAssociationId = associationId;
|
||||
this.mRemoteIn = new ParcelFileDescriptor.AutoCloseInputStream(fd);
|
||||
this.mRemoteOut = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
|
||||
this.mContext = context;
|
||||
this.mListener = listener;
|
||||
}
|
||||
|
||||
public abstract void start();
|
||||
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) {
|
||||
if (DEBUG) Slog.d(TAG, "Requesting for response");
|
||||
@@ -137,6 +99,9 @@ public abstract class Transport {
|
||||
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)
|
||||
throws IOException {
|
||||
if (DEBUG) {
|
||||
@@ -165,11 +130,6 @@ public abstract class Transport {
|
||||
sendMessage(MESSAGE_RESPONSE_SUCCESS, sequence, data);
|
||||
break;
|
||||
}
|
||||
case MESSAGE_REQUEST_PLATFORM_INFO: {
|
||||
callback(message, data);
|
||||
sendMessage(MESSAGE_RESPONSE_SUCCESS, sequence, EmptyArray.BYTE);
|
||||
break;
|
||||
}
|
||||
case MESSAGE_REQUEST_PERMISSION_RESTORE: {
|
||||
if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)
|
||||
&& !Build.isDebuggable()) {
|
||||
@@ -178,7 +138,7 @@ public abstract class Transport {
|
||||
break;
|
||||
}
|
||||
try {
|
||||
callback(message, data);
|
||||
mListener.onRequestPermissionRestore(data);
|
||||
sendMessage(MESSAGE_RESPONSE_SUCCESS, sequence, EmptyArray.BYTE);
|
||||
} catch (Exception e) {
|
||||
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) {
|
||||
final CompletableFuture<byte[]> future;
|
||||
synchronized (mPendingRequests) {
|
||||
|
||||
Reference in New Issue
Block a user