Merge "[CDM] remove platform version exchange protocol" into udc-dev
This commit is contained in:
@@ -19,10 +19,8 @@ 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.companion.AssociationInfo;
|
import android.companion.AssociationInfo;
|
||||||
@@ -33,7 +31,6 @@ import android.content.pm.ApplicationInfo;
|
|||||||
import android.content.pm.PackageManager.NameNotFoundException;
|
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.IBinder;
|
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.os.RemoteCallbackList;
|
import android.os.RemoteCallbackList;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
@@ -46,7 +43,6 @@ import com.android.server.companion.AssociationStore;
|
|||||||
|
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -58,19 +54,8 @@ 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 SECURE_CHANNEL_AVAILABLE_SDK = Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
|
|
||||||
private static final int NON_ANDROID = -1;
|
|
||||||
|
|
||||||
private boolean mSecureTransportEnabled = true;
|
private boolean mSecureTransportEnabled = true;
|
||||||
|
|
||||||
private static boolean isRequest(int message) {
|
|
||||||
return (message & 0xFF000000) == 0x63000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isResponse(int message) {
|
|
||||||
return (message & 0xFF000000) == 0x33000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
private final AssociationStore mAssociationStore;
|
private final AssociationStore mAssociationStore;
|
||||||
|
|
||||||
@@ -84,10 +69,6 @@ public class CompanionTransportManager {
|
|||||||
@NonNull
|
@NonNull
|
||||||
private final SparseArray<IOnMessageReceivedListener> mMessageListeners = new SparseArray<>();
|
private final SparseArray<IOnMessageReceivedListener> mMessageListeners = new SparseArray<>();
|
||||||
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private Transport mTempTransport;
|
|
||||||
|
|
||||||
public CompanionTransportManager(Context context, AssociationStore associationStore) {
|
public CompanionTransportManager(Context context, AssociationStore associationStore) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mAssociationStore = associationStore;
|
mAssociationStore = associationStore;
|
||||||
@@ -199,7 +180,8 @@ public class CompanionTransportManager {
|
|||||||
detachSystemDataTransport(packageName, userId, associationId);
|
detachSystemDataTransport(packageName, userId, associationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
initializeTransport(associationId, fd);
|
// TODO: Implement new API to pass a PSK
|
||||||
|
initializeTransport(associationId, fd, null);
|
||||||
|
|
||||||
notifyOnTransportsChanged();
|
notifyOnTransportsChanged();
|
||||||
}
|
}
|
||||||
@@ -237,107 +219,36 @@ public class CompanionTransportManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeTransport(int associationId, ParcelFileDescriptor fd) {
|
private void initializeTransport(int associationId,
|
||||||
|
ParcelFileDescriptor fd,
|
||||||
|
byte[] preSharedKey) {
|
||||||
Slog.i(TAG, "Initializing transport");
|
Slog.i(TAG, "Initializing transport");
|
||||||
|
Transport transport;
|
||||||
if (!isSecureTransportEnabled()) {
|
if (!isSecureTransportEnabled()) {
|
||||||
Transport transport = new RawTransport(associationId, fd, mContext);
|
// If secure transport is explicitly disabled for testing, use raw transport
|
||||||
|
Slog.i(TAG, "Secure channel is disabled. Creating raw transport");
|
||||||
|
transport = new RawTransport(associationId, fd, mContext);
|
||||||
|
} else if (Build.isDebuggable()) {
|
||||||
|
// If device is debug build, use hardcoded test key for authentication
|
||||||
|
Slog.d(TAG, "Creating an unauthenticated secure channel");
|
||||||
|
final byte[] testKey = "CDM".getBytes(StandardCharsets.UTF_8);
|
||||||
|
transport = new SecureTransport(associationId, fd, mContext, testKey, null);
|
||||||
|
} else if (preSharedKey != null) {
|
||||||
|
// If either device is not Android, then use app-specific pre-shared key
|
||||||
|
Slog.d(TAG, "Creating a PSK-authenticated secure channel");
|
||||||
|
transport = new SecureTransport(associationId, fd, mContext, preSharedKey, null);
|
||||||
|
} else {
|
||||||
|
// If none of the above applies, then use secure channel with attestation verification
|
||||||
|
Slog.d(TAG, "Creating a secure channel");
|
||||||
|
transport = new SecureTransport(associationId, fd, mContext);
|
||||||
|
}
|
||||||
|
|
||||||
addMessageListenersToTransport(transport);
|
addMessageListenersToTransport(transport);
|
||||||
transport.start();
|
transport.start();
|
||||||
synchronized (mTransports) {
|
synchronized (mTransports) {
|
||||||
mTransports.put(associationId, transport);
|
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);
|
|
||||||
addMessageListenersToTransport(mTempTransport);
|
|
||||||
IOnMessageReceivedListener listener = new IOnMessageReceivedListener() {
|
|
||||||
@Override
|
|
||||||
public void onMessageReceived(int associationId, byte[] data) throws RemoteException {
|
|
||||||
synchronized (mTransports) {
|
|
||||||
onPlatformInfoReceived(associationId, data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IBinder asBinder() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
mTempTransport.addListener(MESSAGE_REQUEST_PLATFORM_INFO, listener);
|
|
||||||
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
|
|
||||||
try {
|
|
||||||
mTempTransport.sendMessage(MESSAGE_REQUEST_PLATFORM_INFO, data.array());
|
|
||||||
} catch (IOException e) {
|
|
||||||
Slog.e(TAG, "Failed to exchange platform info");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Depending on the remote platform info to decide which transport should be created
|
|
||||||
*/
|
|
||||||
private void onPlatformInfoReceived(int associationId, byte[] data) {
|
|
||||||
if (mTempTransport.getAssociationId() != associationId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 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.stop();
|
|
||||||
|
|
||||||
int sdk = Build.VERSION.SDK_INT;
|
|
||||||
String release = Build.VERSION.RELEASE;
|
|
||||||
|
|
||||||
if (sdk < SECURE_CHANNEL_AVAILABLE_SDK || remoteSdk < SECURE_CHANNEL_AVAILABLE_SDK) {
|
|
||||||
// If either device is Android T or below, use raw channel
|
|
||||||
// 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
|
|
||||||
Slog.d(TAG, "Secure channel is not supported. Using raw transport");
|
|
||||||
transport = new RawTransport(transport.getAssociationId(), transport.getFd(), mContext);
|
|
||||||
} else if (Build.isDebuggable()) {
|
|
||||||
// If device is debug build, use hardcoded test key for authentication
|
|
||||||
Slog.d(TAG, "Creating an unauthenticated secure channel");
|
|
||||||
final byte[] testKey = "CDM".getBytes(StandardCharsets.UTF_8);
|
|
||||||
transport = new SecureTransport(transport.getAssociationId(), transport.getFd(),
|
|
||||||
mContext, testKey, null);
|
|
||||||
} else if (sdk == NON_ANDROID || remoteSdk == NON_ANDROID) {
|
|
||||||
// If either device is not Android, then use app-specific pre-shared key
|
|
||||||
// TODO: pass in a real preSharedKey
|
|
||||||
Slog.d(TAG, "Creating a PSK-authenticated secure channel");
|
|
||||||
transport = new SecureTransport(transport.getAssociationId(), transport.getFd(),
|
|
||||||
mContext, new byte[0], null);
|
|
||||||
} else {
|
|
||||||
// If none of the above applies, then use secure channel with attestation verification
|
|
||||||
Slog.d(TAG, "Creating a secure channel");
|
|
||||||
transport = new SecureTransport(transport.getAssociationId(), transport.getFd(),
|
|
||||||
mContext);
|
|
||||||
}
|
|
||||||
addMessageListenersToTransport(transport);
|
|
||||||
transport.start();
|
|
||||||
synchronized (mTransports) {
|
|
||||||
mTransports.put(transport.getAssociationId(), transport);
|
|
||||||
}
|
|
||||||
// Doesn't need to notifyTransportsChanged here, it'll be done in attachSystemDataTransport
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Future<?> requestPermissionRestore(int associationId, byte[] data) {
|
public Future<?> requestPermissionRestore(int associationId, byte[] data) {
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ class RawTransport extends Transport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start() {
|
void start() {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Slog.d(TAG, "Starting raw transport.");
|
Slog.d(TAG, "Starting raw transport.");
|
||||||
}
|
}
|
||||||
@@ -54,7 +54,7 @@ class RawTransport extends Transport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stop() {
|
void stop() {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Slog.d(TAG, "Stopping raw transport.");
|
Slog.d(TAG, "Stopping raw transport.");
|
||||||
}
|
}
|
||||||
@@ -62,7 +62,7 @@ class RawTransport extends Transport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
void close() {
|
||||||
stop();
|
stop();
|
||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
|
|||||||
@@ -51,18 +51,18 @@ class SecureTransport extends Transport implements SecureChannel.Callback {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start() {
|
void start() {
|
||||||
mSecureChannel.start();
|
mSecureChannel.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stop() {
|
void stop() {
|
||||||
mSecureChannel.stop();
|
mSecureChannel.stop();
|
||||||
mShouldProcessRequests = false;
|
mShouldProcessRequests = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
void close() {
|
||||||
mSecureChannel.close();
|
mSecureChannel.close();
|
||||||
mShouldProcessRequests = false;
|
mShouldProcessRequests = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,6 @@ public abstract class Transport {
|
|||||||
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 = 0x63807073; // ?PFI
|
|
||||||
public static final int MESSAGE_REQUEST_CONTEXT_SYNC = 0x63678883; // ?CXS
|
public static final int MESSAGE_REQUEST_CONTEXT_SYNC = 0x63678883; // ?CXS
|
||||||
public static final int MESSAGE_REQUEST_PERMISSION_RESTORE = 0x63826983; // ?RES
|
public static final int MESSAGE_REQUEST_PERMISSION_RESTORE = 0x63826983; // ?RES
|
||||||
|
|
||||||
@@ -113,17 +112,17 @@ public abstract class Transport {
|
|||||||
/**
|
/**
|
||||||
* Start listening to messages.
|
* Start listening to messages.
|
||||||
*/
|
*/
|
||||||
public abstract void start();
|
abstract void start();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Soft stop listening to the incoming data without closing the streams.
|
* Soft stop listening to the incoming data without closing the streams.
|
||||||
*/
|
*/
|
||||||
public 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.
|
||||||
*/
|
*/
|
||||||
public abstract void close();
|
abstract void close();
|
||||||
|
|
||||||
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;
|
||||||
@@ -183,11 +182,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);
|
|
||||||
// DO NOT SEND A RESPONSE!
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case MESSAGE_REQUEST_CONTEXT_SYNC: {
|
case MESSAGE_REQUEST_CONTEXT_SYNC: {
|
||||||
callback(message, data);
|
callback(message, data);
|
||||||
sendMessage(MESSAGE_RESPONSE_SUCCESS, sequence, EmptyArray.BYTE);
|
sendMessage(MESSAGE_RESPONSE_SUCCESS, sequence, EmptyArray.BYTE);
|
||||||
|
|||||||
Reference in New Issue
Block a user