Merge "Detach CDM transport upon encountering an secure channel error" into udc-dev am: 79125d4383 am: a06ae8036c

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

Change-Id: I331f592332e75f3ea0aeb93ecd742ece54b97369
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Raphael Kim
2023-06-21 18:13:54 +00:00
committed by Automerger Merge Worker
5 changed files with 72 additions and 34 deletions

View File

@@ -130,6 +130,7 @@ public class SecureChannel {
if (DEBUG) {
Slog.d(TAG, "Starting secure channel.");
}
mStopped = false;
new Thread(() -> {
try {
// 1. Wait for the next handshake message and process it.
@@ -184,6 +185,17 @@ public class SecureChannel {
KeyStoreUtils.cleanUp(mAlias);
}
/**
* Return true if the channel is currently inactive.
* The channel could have been stopped by either {@link SecureChannel#stop()} or by
* encountering a fatal error.
*
* @return true if the channel is currently inactive.
*/
public boolean isStopped() {
return mStopped;
}
/**
* Start exchanging handshakes to create a secure layer asynchronously. When the handshake is
* completed successfully, then the {@link Callback#onSecureConnection()} will trigger. Any
@@ -290,6 +302,7 @@ public class SecureChannel {
try {
data = new byte[length];
} catch (OutOfMemoryError error) {
Streams.skipByReading(mInput, Long.MAX_VALUE);
throw new SecureChannelException("Payload is too large.", error);
}

View File

@@ -137,13 +137,7 @@ public class CompanionTransportManager {
synchronized (mTransports) {
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]);
}
mTransports.get(associationIds[i]).requestForResponse(message, data);
}
}
}
@@ -244,6 +238,7 @@ public class CompanionTransportManager {
}
addMessageListenersToTransport(transport);
transport.setOnTransportClosedListener(this::detachSystemDataTransport);
transport.start();
synchronized (mTransports) {
mTransports.put(associationId, transport);
@@ -321,4 +316,14 @@ public class CompanionTransportManager {
transport.addListener(mMessageListeners.keyAt(i), mMessageListeners.valueAt(i));
}
}
void detachSystemDataTransport(Transport transport) {
int associationId = transport.mAssociationId;
AssociationInfo association = mAssociationStore.getAssociationById(associationId);
if (association != null) {
detachSystemDataTransport(association.getPackageName(),
association.getUserId(),
association.getId());
}
}
}

View File

@@ -70,6 +70,8 @@ class RawTransport extends Transport {
}
IoUtils.closeQuietly(mRemoteIn);
IoUtils.closeQuietly(mRemoteOut);
super.close();
}
@Override

View File

@@ -21,7 +21,6 @@ import android.content.Context;
import android.os.ParcelFileDescriptor;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.server.companion.securechannel.AttestationVerifier;
import com.android.server.companion.securechannel.SecureChannel;
@@ -35,7 +34,6 @@ class SecureTransport extends Transport implements SecureChannel.Callback {
private volatile boolean mShouldProcessRequests = false;
@GuardedBy("mRequestQueue")
private final BlockingQueue<byte[]> mRequestQueue = new ArrayBlockingQueue<>(100);
SecureTransport(int associationId, ParcelFileDescriptor fd, Context context) {
@@ -64,6 +62,8 @@ class SecureTransport extends Transport implements SecureChannel.Callback {
void close() {
mSecureChannel.close();
mShouldProcessRequests = false;
super.close();
}
@Override
@@ -81,13 +81,19 @@ class SecureTransport extends Transport implements SecureChannel.Callback {
}
// Queue up a message to send
synchronized (mRequestQueue) {
try {
mRequestQueue.add(ByteBuffer.allocate(HEADER_LENGTH + data.length)
.putInt(message)
.putInt(sequence)
.putInt(data.length)
.put(data)
.array());
} catch (IllegalStateException e) {
// Request buffer can only be full if too many requests are being added or
// the request processing thread is dead. Assume latter and detach the transport.
Slog.w(TAG, "Failed to queue message 0x" + Integer.toHexString(message)
+ " . Request buffer is full; detaching transport.", e);
close();
}
}
@@ -96,8 +102,8 @@ class SecureTransport extends Transport implements SecureChannel.Callback {
try {
mSecureChannel.establishSecureConnection();
} catch (Exception e) {
Slog.w(TAG, "Failed to initiate secure channel handshake.", e);
onError(e);
Slog.e(TAG, "Failed to initiate secure channel handshake.", e);
close();
}
}
@@ -108,17 +114,14 @@ class SecureTransport extends Transport implements SecureChannel.Callback {
// TODO: find a better way to handle incoming requests than a dedicated thread.
new Thread(() -> {
try {
while (mShouldProcessRequests) {
synchronized (mRequestQueue) {
byte[] request = mRequestQueue.poll();
if (request != null) {
mSecureChannel.sendSecureMessage(request);
}
}
while (mShouldProcessRequests) {
try {
byte[] request = mRequestQueue.take();
mSecureChannel.sendSecureMessage(request);
} catch (Exception e) {
Slog.e(TAG, "Failed to send secure message.", e);
close();
}
} catch (IOException e) {
onError(e);
}
}).start();
}
@@ -135,13 +138,18 @@ class SecureTransport extends Transport implements SecureChannel.Callback {
try {
handleMessage(message, sequence, content);
} catch (IOException error) {
onError(error);
// IOException won't be thrown here because a separate thread is handling
// the write operations inside onSecureConnection().
}
}
@Override
public void onError(Throwable error) {
mShouldProcessRequests = false;
Slog.e(TAG, error.getMessage(), error);
Slog.e(TAG, "Secure transport encountered an error.", error);
// If the channel was stopped as a result of the error, then detach itself.
if (mSecureChannel.isStopped()) {
close();
}
}
}

View File

@@ -70,6 +70,8 @@ public abstract class Transport {
*/
private final Map<Integer, IOnMessageReceivedListener> mListeners;
private OnTransportClosedListener mOnTransportClosed;
private static boolean isRequest(int message) {
return (message & 0xFF000000) == 0x63000000;
}
@@ -120,20 +122,18 @@ public abstract class Transport {
abstract void stop();
/**
* Stop listening to the incoming data and close the streams.
* Stop listening to the incoming data and close the streams. If a listener for closed event
* is set, then trigger it to assist with its clean-up.
*/
abstract void close();
void close() {
if (mOnTransportClosed != null) {
mOnTransportClosed.onClosed(this);
}
}
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();
@@ -247,4 +247,14 @@ public abstract class Transport {
}
}
}
void setOnTransportClosedListener(OnTransportClosedListener callback) {
this.mOnTransportClosed = callback;
}
// Interface to pass transport to the transport manager to assist with detachment.
@FunctionalInterface
interface OnTransportClosedListener {
void onClosed(Transport transport);
}
}