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

Commit 84846143 authored by Raphael Kim's avatar Raphael Kim Committed by Automerger Merge Worker
Browse files

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

parents 03ed2498 79125d43
Loading
Loading
Loading
Loading
+13 −0
Original line number Original line Diff line number Diff line
@@ -130,6 +130,7 @@ public class SecureChannel {
        if (DEBUG) {
        if (DEBUG) {
            Slog.d(TAG, "Starting secure channel.");
            Slog.d(TAG, "Starting secure channel.");
        }
        }
        mStopped = false;
        new Thread(() -> {
        new Thread(() -> {
            try {
            try {
                // 1. Wait for the next handshake message and process it.
                // 1. Wait for the next handshake message and process it.
@@ -184,6 +185,17 @@ public class SecureChannel {
        KeyStoreUtils.cleanUp(mAlias);
        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
     * Start exchanging handshakes to create a secure layer asynchronously. When the handshake is
     * completed successfully, then the {@link Callback#onSecureConnection()} will trigger. Any
     * completed successfully, then the {@link Callback#onSecureConnection()} will trigger. Any
@@ -290,6 +302,7 @@ public class SecureChannel {
            try {
            try {
                data = new byte[length];
                data = new byte[length];
            } catch (OutOfMemoryError error) {
            } catch (OutOfMemoryError error) {
                Streams.skipByReading(mInput, Long.MAX_VALUE);
                throw new SecureChannelException("Payload is too large.", error);
                throw new SecureChannelException("Payload is too large.", error);
            }
            }


+12 −7
Original line number Original line Diff line number Diff line
@@ -137,13 +137,7 @@ public class CompanionTransportManager {
        synchronized (mTransports) {
        synchronized (mTransports) {
            for (int i = 0; i < associationIds.length; i++) {
            for (int i = 0; i < associationIds.length; i++) {
                if (mTransports.contains(associationIds[i])) {
                if (mTransports.contains(associationIds[i])) {
                    try {
                    mTransports.get(associationIds[i]).requestForResponse(message, data);
                        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]);
                    }
                }
                }
            }
            }
        }
        }
@@ -244,6 +238,7 @@ public class CompanionTransportManager {
        }
        }


        addMessageListenersToTransport(transport);
        addMessageListenersToTransport(transport);
        transport.setOnTransportClosedListener(this::detachSystemDataTransport);
        transport.start();
        transport.start();
        synchronized (mTransports) {
        synchronized (mTransports) {
            mTransports.put(associationId, transport);
            mTransports.put(associationId, transport);
@@ -321,4 +316,14 @@ public class CompanionTransportManager {
            transport.addListener(mMessageListeners.keyAt(i), mMessageListeners.valueAt(i));
            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 Original line Diff line number Diff line
@@ -70,6 +70,8 @@ class RawTransport extends Transport {
        }
        }
        IoUtils.closeQuietly(mRemoteIn);
        IoUtils.closeQuietly(mRemoteIn);
        IoUtils.closeQuietly(mRemoteOut);
        IoUtils.closeQuietly(mRemoteOut);

        super.close();
    }
    }


    @Override
    @Override
+26 −18
Original line number Original line Diff line number Diff line
@@ -21,7 +21,6 @@ import android.content.Context;
import android.os.ParcelFileDescriptor;
import android.os.ParcelFileDescriptor;
import android.util.Slog;
import android.util.Slog;


import com.android.internal.annotations.GuardedBy;
import com.android.server.companion.securechannel.AttestationVerifier;
import com.android.server.companion.securechannel.AttestationVerifier;
import com.android.server.companion.securechannel.SecureChannel;
import com.android.server.companion.securechannel.SecureChannel;


@@ -35,7 +34,6 @@ class SecureTransport extends Transport implements SecureChannel.Callback {


    private volatile boolean mShouldProcessRequests = false;
    private volatile boolean mShouldProcessRequests = false;


    @GuardedBy("mRequestQueue")
    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, ParcelFileDescriptor fd, Context context) {
@@ -64,6 +62,8 @@ class SecureTransport extends Transport implements SecureChannel.Callback {
    void close() {
    void close() {
        mSecureChannel.close();
        mSecureChannel.close();
        mShouldProcessRequests = false;
        mShouldProcessRequests = false;

        super.close();
    }
    }


    @Override
    @Override
@@ -81,13 +81,19 @@ class SecureTransport extends Transport implements SecureChannel.Callback {
        }
        }


        // Queue up a message to send
        // Queue up a message to send
        synchronized (mRequestQueue) {
        try {
            mRequestQueue.add(ByteBuffer.allocate(HEADER_LENGTH + data.length)
            mRequestQueue.add(ByteBuffer.allocate(HEADER_LENGTH + data.length)
                    .putInt(message)
                    .putInt(message)
                    .putInt(sequence)
                    .putInt(sequence)
                    .putInt(data.length)
                    .putInt(data.length)
                    .put(data)
                    .put(data)
                    .array());
                    .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 {
        try {
            mSecureChannel.establishSecureConnection();
            mSecureChannel.establishSecureConnection();
        } catch (Exception e) {
        } catch (Exception e) {
            Slog.w(TAG, "Failed to initiate secure channel handshake.", e);
            Slog.e(TAG, "Failed to initiate secure channel handshake.", e);
            onError(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.
        // TODO: find a better way to handle incoming requests than a dedicated thread.
        new Thread(() -> {
        new Thread(() -> {
            try {
            while (mShouldProcessRequests) {
            while (mShouldProcessRequests) {
                    synchronized (mRequestQueue) {
                try {
                        byte[] request = mRequestQueue.poll();
                    byte[] request = mRequestQueue.take();
                        if (request != null) {
                    mSecureChannel.sendSecureMessage(request);
                    mSecureChannel.sendSecureMessage(request);
                } catch (Exception e) {
                    Slog.e(TAG, "Failed to send secure message.", e);
                    close();
                }
                }
            }
            }
                }
            } catch (IOException e) {
                onError(e);
            }
        }).start();
        }).start();
    }
    }


@@ -135,13 +138,18 @@ class SecureTransport extends Transport implements SecureChannel.Callback {
        try {
        try {
            handleMessage(message, sequence, content);
            handleMessage(message, sequence, content);
        } catch (IOException error) {
        } catch (IOException error) {
            onError(error);
            // IOException won't be thrown here because a separate thread is handling
            // the write operations inside onSecureConnection().
        }
        }
    }
    }


    @Override
    @Override
    public void onError(Throwable error) {
    public void onError(Throwable error) {
        mShouldProcessRequests = false;
        Slog.e(TAG, "Secure transport encountered an error.", error);
        Slog.e(TAG, error.getMessage(), error);

        // If the channel was stopped as a result of the error, then detach itself.
        if (mSecureChannel.isStopped()) {
            close();
        }
    }
    }
}
}
+19 −9
Original line number Original line Diff line number Diff line
@@ -70,6 +70,8 @@ public abstract class Transport {
     */
     */
    private final Map<Integer, IOnMessageReceivedListener> mListeners;
    private final Map<Integer, IOnMessageReceivedListener> mListeners;


    private OnTransportClosedListener mOnTransportClosed;

    private static boolean isRequest(int message) {
    private static boolean isRequest(int message) {
        return (message & 0xFF000000) == 0x63000000;
        return (message & 0xFF000000) == 0x63000000;
    }
    }
@@ -120,20 +122,18 @@ public abstract class Transport {
    abstract void stop();
    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)
    protected abstract void sendMessage(int message, int sequence, @NonNull byte[] data)
            throws IOException;
            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) {
    public Future<byte[]> requestForResponse(int message, byte[] data) {
        if (DEBUG) Slog.d(TAG, "Requesting for response");
        if (DEBUG) Slog.d(TAG, "Requesting for response");
        final int sequence = mNextSequence.incrementAndGet();
        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);
    }
}
}