Loading services/companion/java/com/android/server/companion/CompanionApplicationController.java +27 −2 Original line number Diff line number Diff line Loading @@ -62,7 +62,7 @@ import java.util.Map; * @see CompanionDeviceServiceConnector */ @SuppressLint("LongLogTag") class CompanionApplicationController { public class CompanionApplicationController { static final boolean DEBUG = false; private static final String TAG = "CompanionDevice_ApplicationController"; Loading Loading @@ -164,7 +164,10 @@ class CompanionApplicationController { } } boolean isCompanionApplicationBound(@UserIdInt int userId, @NonNull String packageName) { /** * @return whether the companion application is bound now. */ public boolean isCompanionApplicationBound(@UserIdInt int userId, @NonNull String packageName) { synchronized (mBoundCompanionApplications) { return mBoundCompanionApplications.containsValueForPackage(userId, packageName); } Loading Loading @@ -234,6 +237,28 @@ class CompanionApplicationController { primaryServiceConnector.postOnDeviceDisappeared(association); } /** Pass an encryped secure message to the companion application for transporting. */ public void dispatchMessage(@UserIdInt int userId, @NonNull String packageName, int associationId, @NonNull byte[] message) { if (DEBUG) { Log.i(TAG, "dispatchMessage() u" + userId + "/" + packageName + " associationId=" + associationId); } final CompanionDeviceServiceConnector primaryServiceConnector = getPrimaryServiceConnector(userId, packageName); if (primaryServiceConnector == null) { if (DEBUG) { Log.e(TAG, "dispatchMessage(): " + "u" + userId + "/" + packageName + " is NOT bound."); Log.d(TAG, "Stacktrace", new Throwable()); } return; } primaryServiceConnector.postOnMessageDispatchedFromSystem(associationId, message); } private void onPrimaryServiceBindingDied(@UserIdInt int userId, @NonNull String packageName) { if (DEBUG) Log.i(TAG, "onPrimaryServiceBindingDied() u" + userId + "/" + packageName); Loading services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +17 −8 Original line number Diff line number Diff line Loading @@ -83,6 +83,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.text.BidiFormatter; import android.util.ArraySet; import android.util.Base64; import android.util.ExceptionUtils; import android.util.Log; import android.util.Slog; Loading @@ -102,6 +103,7 @@ import com.android.server.SystemService; import com.android.server.companion.datatransfer.SystemDataTransferProcessor; import com.android.server.companion.datatransfer.SystemDataTransferRequestStore; import com.android.server.companion.presence.CompanionDevicePresenceMonitor; import com.android.server.companion.securechannel.CompanionSecureCommunicationsManager; import com.android.server.pm.UserManagerInternal; import java.io.File; Loading Loading @@ -137,6 +139,7 @@ public class CompanionDeviceManagerService extends SystemService { private SystemDataTransferProcessor mSystemDataTransferProcessor; private CompanionDevicePresenceMonitor mDevicePresenceMonitor; private CompanionApplicationController mCompanionAppController; private CompanionSecureCommunicationsManager mSecureCommsManager; private final ActivityManagerInternal mAmInternal; private final IAppOpsService mAppOpsManager; Loading Loading @@ -173,6 +176,8 @@ public class CompanionDeviceManagerService extends SystemService { @Override public void onStart() { final Context context = getContext(); mPersistentStore = new PersistentDataStore(); loadAssociationsFromDisk(); Loading @@ -185,10 +190,10 @@ public class CompanionDeviceManagerService extends SystemService { /* cdmService */this, mAssociationStore); mSystemDataTransferProcessor = new SystemDataTransferProcessor(this, mAssociationStore, mSystemDataTransferRequestStore); final Context context = getContext(); mCompanionAppController = new CompanionApplicationController( context, mApplicationControllerCallback); mSecureCommsManager = new CompanionSecureCommunicationsManager( mAssociationStore, mCompanionAppController); // Publish "binder" service. final CompanionDeviceManagerImpl impl = new CompanionDeviceManagerImpl(); Loading Loading @@ -257,7 +262,7 @@ public class CompanionDeviceManagerService extends SystemService { if (DEBUG) Log.i(TAG, "onDevice_Appeared_Internal() id=" + associationId); final AssociationInfo association = mAssociationStore.getAssociationById(associationId); if (DEBUG) Log.d(TAG, " association=" + associationId); if (DEBUG) Log.d(TAG, " association=" + association); if (!association.shouldBindWhenPresent()) return; Loading @@ -279,7 +284,7 @@ public class CompanionDeviceManagerService extends SystemService { if (DEBUG) Log.i(TAG, "onDevice_Disappeared_Internal() id=" + associationId); final AssociationInfo association = mAssociationStore.getAssociationById(associationId); if (DEBUG) Log.d(TAG, " association=" + associationId); if (DEBUG) Log.d(TAG, " association=" + association); final int userId = association.getUserId(); final String packageName = association.getPackageName(); Loading Loading @@ -603,9 +608,13 @@ public class CompanionDeviceManagerService extends SystemService { } @Override public void dispatchMessage(int messageId, int associationId, byte[] message) throws RemoteException { // TODO(b/199427116): implement. public void dispatchMessage(int messageId, int associationId, @NonNull byte[] message) { if (DEBUG) { Log.i(TAG, "dispatchMessage() associationId=" + associationId + "\n" + " message(Base64)=" + Base64.encodeToString(message, 0)); } mSecureCommsManager.receiveSecureMessage(associationId, message); } @Override Loading Loading @@ -743,7 +752,7 @@ public class CompanionDeviceManagerService extends SystemService { throws RemoteException { enforceCallerCanManageCompanionDevice(getContext(), "onShellCommand"); new CompanionDeviceShellCommand( CompanionDeviceManagerService.this, mAssociationStore) CompanionDeviceManagerService.this, mAssociationStore, mSecureCommsManager) .exec(this, in, out, err, args, callback, resultReceiver); } Loading services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java +11 −0 Original line number Diff line number Diff line Loading @@ -98,6 +98,17 @@ class CompanionDeviceServiceConnector extends ServiceConnector.Impl<ICompanionDe post(companionService -> companionService.onDeviceDisappeared(associationInfo)); } void postOnMessageDispatchedFromSystem(int associationId, @NonNull byte[] message) { // We always use messageId 0 (at least for now). // Unlike the message itself, the messageId is not encoded, which means that the CDM on the // other (receiving) end CAN NOT and MUST NOT trust this messageId. // If CDM needs to pass messageId around to the other side - it should embed it in the // message body. post(companionService -> companionService.onMessageDispatchedFromSystem( /* messageId*/ 0, associationId, message)); } /** * Post "unbind" job, which will run *after* all previously posted jobs complete. * Loading services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java +48 −14 Original line number Diff line number Diff line Loading @@ -16,10 +16,13 @@ package com.android.server.companion; import static java.nio.charset.StandardCharsets.UTF_8; import android.companion.AssociationInfo; import android.os.ShellCommand; import android.util.Log; import android.util.Slog; import android.util.Base64; import com.android.server.companion.securechannel.CompanionSecureCommunicationsManager; import java.io.PrintWriter; import java.util.List; Loading @@ -29,11 +32,14 @@ class CompanionDeviceShellCommand extends ShellCommand { private final CompanionDeviceManagerService mService; private final AssociationStore mAssociationStore; private final CompanionSecureCommunicationsManager mSecureCommsManager; CompanionDeviceShellCommand(CompanionDeviceManagerService service, AssociationStore associationStore) { AssociationStore associationStore, CompanionSecureCommunicationsManager secureCommsManager) { mService = service; mAssociationStore = associationStore; mSecureCommsManager = secureCommsManager; } @Override Loading @@ -42,7 +48,7 @@ class CompanionDeviceShellCommand extends ShellCommand { try { switch (cmd) { case "list": { final int userId = getNextArgInt(); final int userId = getNextIntArgRequired(); final List<AssociationInfo> associationsForUser = mAssociationStore.getAssociationsForUser(userId); for (AssociationInfo association : associationsForUser) { Loading @@ -55,7 +61,7 @@ class CompanionDeviceShellCommand extends ShellCommand { break; case "associate": { int userId = getNextArgInt(); int userId = getNextIntArgRequired(); String packageName = getNextArgRequired(); String address = getNextArgRequired(); mService.legacyCreateAssociation(userId, address, packageName, null); Loading @@ -63,7 +69,7 @@ class CompanionDeviceShellCommand extends ShellCommand { break; case "disassociate": { final int userId = getNextArgInt(); final int userId = getNextIntArgRequired(); final String packageName = getNextArgRequired(); final String address = getNextArgRequired(); final AssociationInfo association = Loading @@ -74,24 +80,50 @@ class CompanionDeviceShellCommand extends ShellCommand { } break; case "clear-association-memory-cache": { case "clear-association-memory-cache": mService.persistState(); mService.loadAssociationsFromDisk(); break; case "send-secure-message": final int associationId = getNextIntArgRequired(); final byte[] message; // The message should be either a UTF-8 String or Base64-encoded data. final boolean isBase64 = "--base64".equals(getNextOption()); if (isBase64) { final String base64encodedMessage = getNextArgRequired(); message = Base64.decode(base64encodedMessage, 0); } else { // We treat the rest of the command as the message, which should contain at // least one word (hence getNextArg_Required() below), but there may be // more. final StringBuilder sb = new StringBuilder(getNextArgRequired()); // Pick up the rest. for (String word : peekRemainingArgs()) { sb.append(" ").append(word); } // And now convert to byte[]... message = sb.toString().getBytes(UTF_8); } mSecureCommsManager.sendSecureMessage(associationId, message); break; default: return handleDefaultCommands(cmd); } return 0; } catch (Throwable t) { Slog.e(TAG, "Error running a command: $ " + cmd, t); getErrPrintWriter().println(Log.getStackTraceString(t)); } catch (Throwable e) { final PrintWriter errOut = getErrPrintWriter(); errOut.println(); errOut.println("Exception occurred while executing '" + cmd + "':"); e.printStackTrace(errOut); return 1; } return 0; } private int getNextArgInt() { private int getNextIntArgRequired() { return Integer.parseInt(getNextArgRequired()); } Loading @@ -107,6 +139,8 @@ class CompanionDeviceShellCommand extends ShellCommand { pw.println(" Create a new Association."); pw.println(" disassociate USER_ID PACKAGE MAC_ADDRESS"); pw.println(" Remove an existing Association."); pw.println(" send-secure-message ASSOCIATION_ID [--base64] MESSAGE"); pw.println(" Send a secure message to an associated companion device."); pw.println(" clear-association-memory-cache"); pw.println(" Clear the in-memory association cache and reload all association " + "information from persistent storage. USE FOR DEBUGGING PURPOSES ONLY."); Loading services/companion/java/com/android/server/companion/securechannel/CompanionSecureCommunicationsManager.java 0 → 100644 +87 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.companion.securechannel; import android.annotation.NonNull; import android.annotation.SuppressLint; import android.companion.AssociationInfo; import android.util.Base64; import android.util.Log; import com.android.server.companion.AssociationStore; import com.android.server.companion.CompanionApplicationController; /** Secure Comms Manager */ @SuppressLint("LongLogTag") public class CompanionSecureCommunicationsManager { static final String TAG = "CompanionDevice_SecureComms"; static final boolean DEBUG = false; private final AssociationStore mAssociationStore; private final CompanionApplicationController mCompanionAppController; /** Constructor */ public CompanionSecureCommunicationsManager(AssociationStore associationStore, CompanionApplicationController companionApplicationController) { mAssociationStore = associationStore; mCompanionAppController = companionApplicationController; } /** * Send a data to the associated companion device via secure channel (establishing one if * needed). * @param associationId associationId of the "recipient" companion device. * @param message data to be sent securely. */ public void sendSecureMessage(int associationId, @NonNull byte[] message) { if (DEBUG) { Log.d(TAG, "sendSecureMessage() associationId=" + associationId + "\n" + " message (Base64)=\"" + Base64.encodeToString(message, 0) + "\""); } final AssociationInfo association = mAssociationStore.getAssociationById(associationId); if (association == null) { throw new IllegalArgumentException( "Association with ID " + associationId + " does not exist"); } if (DEBUG) Log.d(TAG, " association=" + association); final int userId = association.getUserId(); final String packageName = association.getPackageName(); if (!mCompanionAppController.isCompanionApplicationBound(userId, packageName)) { throw new IllegalStateException("u" + userId + "\\" + packageName + " is NOT bound"); } // TODO(b/202926196): implement: encrypt and pass on the companion application for // transporting mCompanionAppController.dispatchMessage(userId, packageName, associationId, message); } /** * Decrypt and dispatch message received from an associated companion device. * @param associationId associationId of the "sender" companion device. * @param encryptedMessage data. */ public void receiveSecureMessage(int associationId, @NonNull byte[] encryptedMessage) { if (DEBUG) { Log.d(TAG, "sendSecureMessage() associationId=" + associationId + "\n" + " message (Base64)=\"" + Base64.encodeToString(encryptedMessage, 0) + "\""); } // TODO(b/202926196): implement: decrypt and dispatch. } } Loading
services/companion/java/com/android/server/companion/CompanionApplicationController.java +27 −2 Original line number Diff line number Diff line Loading @@ -62,7 +62,7 @@ import java.util.Map; * @see CompanionDeviceServiceConnector */ @SuppressLint("LongLogTag") class CompanionApplicationController { public class CompanionApplicationController { static final boolean DEBUG = false; private static final String TAG = "CompanionDevice_ApplicationController"; Loading Loading @@ -164,7 +164,10 @@ class CompanionApplicationController { } } boolean isCompanionApplicationBound(@UserIdInt int userId, @NonNull String packageName) { /** * @return whether the companion application is bound now. */ public boolean isCompanionApplicationBound(@UserIdInt int userId, @NonNull String packageName) { synchronized (mBoundCompanionApplications) { return mBoundCompanionApplications.containsValueForPackage(userId, packageName); } Loading Loading @@ -234,6 +237,28 @@ class CompanionApplicationController { primaryServiceConnector.postOnDeviceDisappeared(association); } /** Pass an encryped secure message to the companion application for transporting. */ public void dispatchMessage(@UserIdInt int userId, @NonNull String packageName, int associationId, @NonNull byte[] message) { if (DEBUG) { Log.i(TAG, "dispatchMessage() u" + userId + "/" + packageName + " associationId=" + associationId); } final CompanionDeviceServiceConnector primaryServiceConnector = getPrimaryServiceConnector(userId, packageName); if (primaryServiceConnector == null) { if (DEBUG) { Log.e(TAG, "dispatchMessage(): " + "u" + userId + "/" + packageName + " is NOT bound."); Log.d(TAG, "Stacktrace", new Throwable()); } return; } primaryServiceConnector.postOnMessageDispatchedFromSystem(associationId, message); } private void onPrimaryServiceBindingDied(@UserIdInt int userId, @NonNull String packageName) { if (DEBUG) Log.i(TAG, "onPrimaryServiceBindingDied() u" + userId + "/" + packageName); Loading
services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +17 −8 Original line number Diff line number Diff line Loading @@ -83,6 +83,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.text.BidiFormatter; import android.util.ArraySet; import android.util.Base64; import android.util.ExceptionUtils; import android.util.Log; import android.util.Slog; Loading @@ -102,6 +103,7 @@ import com.android.server.SystemService; import com.android.server.companion.datatransfer.SystemDataTransferProcessor; import com.android.server.companion.datatransfer.SystemDataTransferRequestStore; import com.android.server.companion.presence.CompanionDevicePresenceMonitor; import com.android.server.companion.securechannel.CompanionSecureCommunicationsManager; import com.android.server.pm.UserManagerInternal; import java.io.File; Loading Loading @@ -137,6 +139,7 @@ public class CompanionDeviceManagerService extends SystemService { private SystemDataTransferProcessor mSystemDataTransferProcessor; private CompanionDevicePresenceMonitor mDevicePresenceMonitor; private CompanionApplicationController mCompanionAppController; private CompanionSecureCommunicationsManager mSecureCommsManager; private final ActivityManagerInternal mAmInternal; private final IAppOpsService mAppOpsManager; Loading Loading @@ -173,6 +176,8 @@ public class CompanionDeviceManagerService extends SystemService { @Override public void onStart() { final Context context = getContext(); mPersistentStore = new PersistentDataStore(); loadAssociationsFromDisk(); Loading @@ -185,10 +190,10 @@ public class CompanionDeviceManagerService extends SystemService { /* cdmService */this, mAssociationStore); mSystemDataTransferProcessor = new SystemDataTransferProcessor(this, mAssociationStore, mSystemDataTransferRequestStore); final Context context = getContext(); mCompanionAppController = new CompanionApplicationController( context, mApplicationControllerCallback); mSecureCommsManager = new CompanionSecureCommunicationsManager( mAssociationStore, mCompanionAppController); // Publish "binder" service. final CompanionDeviceManagerImpl impl = new CompanionDeviceManagerImpl(); Loading Loading @@ -257,7 +262,7 @@ public class CompanionDeviceManagerService extends SystemService { if (DEBUG) Log.i(TAG, "onDevice_Appeared_Internal() id=" + associationId); final AssociationInfo association = mAssociationStore.getAssociationById(associationId); if (DEBUG) Log.d(TAG, " association=" + associationId); if (DEBUG) Log.d(TAG, " association=" + association); if (!association.shouldBindWhenPresent()) return; Loading @@ -279,7 +284,7 @@ public class CompanionDeviceManagerService extends SystemService { if (DEBUG) Log.i(TAG, "onDevice_Disappeared_Internal() id=" + associationId); final AssociationInfo association = mAssociationStore.getAssociationById(associationId); if (DEBUG) Log.d(TAG, " association=" + associationId); if (DEBUG) Log.d(TAG, " association=" + association); final int userId = association.getUserId(); final String packageName = association.getPackageName(); Loading Loading @@ -603,9 +608,13 @@ public class CompanionDeviceManagerService extends SystemService { } @Override public void dispatchMessage(int messageId, int associationId, byte[] message) throws RemoteException { // TODO(b/199427116): implement. public void dispatchMessage(int messageId, int associationId, @NonNull byte[] message) { if (DEBUG) { Log.i(TAG, "dispatchMessage() associationId=" + associationId + "\n" + " message(Base64)=" + Base64.encodeToString(message, 0)); } mSecureCommsManager.receiveSecureMessage(associationId, message); } @Override Loading Loading @@ -743,7 +752,7 @@ public class CompanionDeviceManagerService extends SystemService { throws RemoteException { enforceCallerCanManageCompanionDevice(getContext(), "onShellCommand"); new CompanionDeviceShellCommand( CompanionDeviceManagerService.this, mAssociationStore) CompanionDeviceManagerService.this, mAssociationStore, mSecureCommsManager) .exec(this, in, out, err, args, callback, resultReceiver); } Loading
services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java +11 −0 Original line number Diff line number Diff line Loading @@ -98,6 +98,17 @@ class CompanionDeviceServiceConnector extends ServiceConnector.Impl<ICompanionDe post(companionService -> companionService.onDeviceDisappeared(associationInfo)); } void postOnMessageDispatchedFromSystem(int associationId, @NonNull byte[] message) { // We always use messageId 0 (at least for now). // Unlike the message itself, the messageId is not encoded, which means that the CDM on the // other (receiving) end CAN NOT and MUST NOT trust this messageId. // If CDM needs to pass messageId around to the other side - it should embed it in the // message body. post(companionService -> companionService.onMessageDispatchedFromSystem( /* messageId*/ 0, associationId, message)); } /** * Post "unbind" job, which will run *after* all previously posted jobs complete. * Loading
services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java +48 −14 Original line number Diff line number Diff line Loading @@ -16,10 +16,13 @@ package com.android.server.companion; import static java.nio.charset.StandardCharsets.UTF_8; import android.companion.AssociationInfo; import android.os.ShellCommand; import android.util.Log; import android.util.Slog; import android.util.Base64; import com.android.server.companion.securechannel.CompanionSecureCommunicationsManager; import java.io.PrintWriter; import java.util.List; Loading @@ -29,11 +32,14 @@ class CompanionDeviceShellCommand extends ShellCommand { private final CompanionDeviceManagerService mService; private final AssociationStore mAssociationStore; private final CompanionSecureCommunicationsManager mSecureCommsManager; CompanionDeviceShellCommand(CompanionDeviceManagerService service, AssociationStore associationStore) { AssociationStore associationStore, CompanionSecureCommunicationsManager secureCommsManager) { mService = service; mAssociationStore = associationStore; mSecureCommsManager = secureCommsManager; } @Override Loading @@ -42,7 +48,7 @@ class CompanionDeviceShellCommand extends ShellCommand { try { switch (cmd) { case "list": { final int userId = getNextArgInt(); final int userId = getNextIntArgRequired(); final List<AssociationInfo> associationsForUser = mAssociationStore.getAssociationsForUser(userId); for (AssociationInfo association : associationsForUser) { Loading @@ -55,7 +61,7 @@ class CompanionDeviceShellCommand extends ShellCommand { break; case "associate": { int userId = getNextArgInt(); int userId = getNextIntArgRequired(); String packageName = getNextArgRequired(); String address = getNextArgRequired(); mService.legacyCreateAssociation(userId, address, packageName, null); Loading @@ -63,7 +69,7 @@ class CompanionDeviceShellCommand extends ShellCommand { break; case "disassociate": { final int userId = getNextArgInt(); final int userId = getNextIntArgRequired(); final String packageName = getNextArgRequired(); final String address = getNextArgRequired(); final AssociationInfo association = Loading @@ -74,24 +80,50 @@ class CompanionDeviceShellCommand extends ShellCommand { } break; case "clear-association-memory-cache": { case "clear-association-memory-cache": mService.persistState(); mService.loadAssociationsFromDisk(); break; case "send-secure-message": final int associationId = getNextIntArgRequired(); final byte[] message; // The message should be either a UTF-8 String or Base64-encoded data. final boolean isBase64 = "--base64".equals(getNextOption()); if (isBase64) { final String base64encodedMessage = getNextArgRequired(); message = Base64.decode(base64encodedMessage, 0); } else { // We treat the rest of the command as the message, which should contain at // least one word (hence getNextArg_Required() below), but there may be // more. final StringBuilder sb = new StringBuilder(getNextArgRequired()); // Pick up the rest. for (String word : peekRemainingArgs()) { sb.append(" ").append(word); } // And now convert to byte[]... message = sb.toString().getBytes(UTF_8); } mSecureCommsManager.sendSecureMessage(associationId, message); break; default: return handleDefaultCommands(cmd); } return 0; } catch (Throwable t) { Slog.e(TAG, "Error running a command: $ " + cmd, t); getErrPrintWriter().println(Log.getStackTraceString(t)); } catch (Throwable e) { final PrintWriter errOut = getErrPrintWriter(); errOut.println(); errOut.println("Exception occurred while executing '" + cmd + "':"); e.printStackTrace(errOut); return 1; } return 0; } private int getNextArgInt() { private int getNextIntArgRequired() { return Integer.parseInt(getNextArgRequired()); } Loading @@ -107,6 +139,8 @@ class CompanionDeviceShellCommand extends ShellCommand { pw.println(" Create a new Association."); pw.println(" disassociate USER_ID PACKAGE MAC_ADDRESS"); pw.println(" Remove an existing Association."); pw.println(" send-secure-message ASSOCIATION_ID [--base64] MESSAGE"); pw.println(" Send a secure message to an associated companion device."); pw.println(" clear-association-memory-cache"); pw.println(" Clear the in-memory association cache and reload all association " + "information from persistent storage. USE FOR DEBUGGING PURPOSES ONLY."); Loading
services/companion/java/com/android/server/companion/securechannel/CompanionSecureCommunicationsManager.java 0 → 100644 +87 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.companion.securechannel; import android.annotation.NonNull; import android.annotation.SuppressLint; import android.companion.AssociationInfo; import android.util.Base64; import android.util.Log; import com.android.server.companion.AssociationStore; import com.android.server.companion.CompanionApplicationController; /** Secure Comms Manager */ @SuppressLint("LongLogTag") public class CompanionSecureCommunicationsManager { static final String TAG = "CompanionDevice_SecureComms"; static final boolean DEBUG = false; private final AssociationStore mAssociationStore; private final CompanionApplicationController mCompanionAppController; /** Constructor */ public CompanionSecureCommunicationsManager(AssociationStore associationStore, CompanionApplicationController companionApplicationController) { mAssociationStore = associationStore; mCompanionAppController = companionApplicationController; } /** * Send a data to the associated companion device via secure channel (establishing one if * needed). * @param associationId associationId of the "recipient" companion device. * @param message data to be sent securely. */ public void sendSecureMessage(int associationId, @NonNull byte[] message) { if (DEBUG) { Log.d(TAG, "sendSecureMessage() associationId=" + associationId + "\n" + " message (Base64)=\"" + Base64.encodeToString(message, 0) + "\""); } final AssociationInfo association = mAssociationStore.getAssociationById(associationId); if (association == null) { throw new IllegalArgumentException( "Association with ID " + associationId + " does not exist"); } if (DEBUG) Log.d(TAG, " association=" + association); final int userId = association.getUserId(); final String packageName = association.getPackageName(); if (!mCompanionAppController.isCompanionApplicationBound(userId, packageName)) { throw new IllegalStateException("u" + userId + "\\" + packageName + " is NOT bound"); } // TODO(b/202926196): implement: encrypt and pass on the companion application for // transporting mCompanionAppController.dispatchMessage(userId, packageName, associationId, message); } /** * Decrypt and dispatch message received from an associated companion device. * @param associationId associationId of the "sender" companion device. * @param encryptedMessage data. */ public void receiveSecureMessage(int associationId, @NonNull byte[] encryptedMessage) { if (DEBUG) { Log.d(TAG, "sendSecureMessage() associationId=" + associationId + "\n" + " message (Base64)=\"" + Base64.encodeToString(encryptedMessage, 0) + "\""); } // TODO(b/202926196): implement: decrypt and dispatch. } }