Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 79125d43 authored by Raphael Kim's avatar Raphael Kim Committed by Android (Google) Code Review
Browse files

Merge "Detach CDM transport upon encountering an secure channel error" into udc-dev

parents 3a310dd2 b5018941
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -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);
            }

+12 −7
Original line number Diff line number Diff line
@@ -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());
        }
    }
}
+2 −0
Original line number Diff line number Diff line
@@ -70,6 +70,8 @@ class RawTransport extends Transport {
        }
        IoUtils.closeQuietly(mRemoteIn);
        IoUtils.closeQuietly(mRemoteOut);

        super.close();
    }

    @Override
+26 −18
Original line number Diff line number Diff line
@@ -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,18 +114,15 @@ 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) {
                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();
        }
    }
}
+19 −9
Original line number Diff line number Diff line
@@ -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);
    }
}