From 592a33f86807a9f372c5925d1c241a1e615b5647 Mon Sep 17 00:00:00 2001 From: Guojing Yuan Date: Mon, 27 Jun 2022 22:15:50 +0000 Subject: [PATCH] [CDM perm sync] Introduce a new startSystemDataTransfer API with callback This new trigger API accpets a callback which would be executed when the system data transfer finishes successfully or with error. The callback hasn't been fully implemented because we need signals from transport layer when the transfer finishes. Bug: 237030169 Test: m builds Change-Id: I7e57d3e53e5f019c8730df10f7ec6c840e446f67 --- core/api/current.txt | 6 +- .../companion/CompanionDeviceManager.java | 56 ++++++++++++++++++- .../android/companion/CompanionException.java | 29 ++++++++++ .../companion/ICompanionDeviceManager.aidl | 4 +- .../ISystemDataTransferCallback.aidl | 24 ++++++++ .../CompanionDeviceManagerService.java | 6 +- .../SystemDataTransferProcessor.java | 6 +- 7 files changed, 125 insertions(+), 6 deletions(-) create mode 100644 core/java/android/companion/CompanionException.java create mode 100644 core/java/android/companion/ISystemDataTransferCallback.aidl diff --git a/core/api/current.txt b/core/api/current.txt index 7eb55eda6be85..1a79f725af0fb 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -9008,7 +9008,8 @@ package android.companion { method @Deprecated public boolean hasNotificationAccess(android.content.ComponentName); method public void requestNotificationAccess(android.content.ComponentName); method @RequiresPermission(android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE) public void startObservingDevicePresence(@NonNull String) throws android.companion.DeviceNotAssociatedException; - method public void startSystemDataTransfer(int) throws android.companion.DeviceNotAssociatedException; + method @Deprecated public void startSystemDataTransfer(int) throws android.companion.DeviceNotAssociatedException; + method public void startSystemDataTransfer(int, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver) throws android.companion.DeviceNotAssociatedException; method @RequiresPermission(android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE) public void stopObservingDevicePresence(@NonNull String) throws android.companion.DeviceNotAssociatedException; field public static final String EXTRA_ASSOCIATION = "android.companion.extra.ASSOCIATION"; field @Deprecated public static final String EXTRA_DEVICE = "android.companion.extra.DEVICE"; @@ -9034,6 +9035,9 @@ package android.companion { field public static final String SERVICE_INTERFACE = "android.companion.CompanionDeviceService"; } + public class CompanionException extends java.lang.RuntimeException { + } + public interface DeviceFilter extends android.os.Parcelable { } diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java index b6b860d42ccb9..1b51faf3d4299 100644 --- a/core/java/android/companion/CompanionDeviceManager.java +++ b/core/java/android/companion/CompanionDeviceManager.java @@ -38,6 +38,7 @@ import android.content.IntentSender; import android.content.pm.PackageManager; import android.net.MacAddress; import android.os.Handler; +import android.os.OutcomeReceiver; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.UserHandle; @@ -964,12 +965,44 @@ public final class CompanionDeviceManager { * @param associationId The unique {@link AssociationInfo#getId ID} assigned to the Association * of the companion device recorded by CompanionDeviceManager * @throws DeviceNotAssociatedException Exception if the companion device is not associated + * + * @deprecated Use {@link #startSystemDataTransfer(int, Executor, OutcomeReceiver)} instead. */ + @Deprecated @UserHandleAware public void startSystemDataTransfer(int associationId) throws DeviceNotAssociatedException { try { mService.startSystemDataTransfer(mContext.getOpPackageName(), mContext.getUserId(), - associationId); + associationId, null); + } catch (RemoteException e) { + ExceptionUtils.propagateIfInstanceOf(e.getCause(), DeviceNotAssociatedException.class); + throw e.rethrowFromSystemServer(); + } + } + + /** + * Start system data transfer which has been previously approved by the user. + * + *

Before calling this method, the app needs to make sure there's a communication channel + * between two devices, and has prompted user consent dialogs built by one of these methods: + * {@link #buildPermissionTransferUserConsentIntent(int)}. + * The transfer may fail if the communication channel is disconnected during the transfer.

+ * + * @param associationId The unique {@link AssociationInfo#getId ID} assigned to the Association + * of the companion device recorded by CompanionDeviceManager + * @param executor The executor which will be used to invoke the result callback. + * @param result The callback to notify the app of the result of the system data transfer. + * @throws DeviceNotAssociatedException Exception if the companion device is not associated + */ + @UserHandleAware + public void startSystemDataTransfer( + int associationId, + @NonNull Executor executor, + @NonNull OutcomeReceiver result) + throws DeviceNotAssociatedException { + try { + mService.startSystemDataTransfer(mContext.getOpPackageName(), mContext.getUserId(), + associationId, new SystemDataTransferCallbackProxy(executor, result)); } catch (RemoteException e) { ExceptionUtils.propagateIfInstanceOf(e.getCause(), DeviceNotAssociatedException.class); throw e.rethrowFromSystemServer(); @@ -1045,6 +1078,27 @@ public final class CompanionDeviceManager { } } + private static class SystemDataTransferCallbackProxy extends ISystemDataTransferCallback.Stub { + private final Executor mExecutor; + private final OutcomeReceiver mCallback; + + private SystemDataTransferCallbackProxy(Executor executor, + OutcomeReceiver callback) { + mExecutor = executor; + mCallback = callback; + } + + @Override + public void onResult() { + mExecutor.execute(() -> mCallback.onResult(null)); + } + + @Override + public void onError(String error) { + mExecutor.execute(() -> mCallback.onError(new CompanionException(error))); + } + } + /** * Representation of an active system data transport. *

diff --git a/core/java/android/companion/CompanionException.java b/core/java/android/companion/CompanionException.java new file mode 100644 index 0000000000000..fb78e8df446e4 --- /dev/null +++ b/core/java/android/companion/CompanionException.java @@ -0,0 +1,29 @@ +/* + * 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 android.companion; + +import android.annotation.NonNull; + +/** + * {@code CompanionException} can be thrown during the companion system data transfer process. + */ +public class CompanionException extends RuntimeException { + /** @hide */ + public CompanionException(@NonNull String message) { + super(message); + } +} diff --git a/core/java/android/companion/ICompanionDeviceManager.aidl b/core/java/android/companion/ICompanionDeviceManager.aidl index ab7dc09cf4595..42f908396799d 100644 --- a/core/java/android/companion/ICompanionDeviceManager.aidl +++ b/core/java/android/companion/ICompanionDeviceManager.aidl @@ -19,6 +19,7 @@ package android.companion; import android.app.PendingIntent; import android.companion.IAssociationRequestCallback; import android.companion.IOnAssociationsChangedListener; +import android.companion.ISystemDataTransferCallback; import android.companion.AssociationInfo; import android.companion.AssociationRequest; import android.content.ComponentName; @@ -75,7 +76,8 @@ interface ICompanionDeviceManager { PendingIntent buildPermissionTransferUserConsentIntent(String callingPackage, int userId, int associationId); - void startSystemDataTransfer(String packageName, int userId, int associationId); + void startSystemDataTransfer(String packageName, int userId, int associationId, + in ISystemDataTransferCallback callback); void attachSystemDataTransport(String packageName, int userId, int associationId, in ParcelFileDescriptor fd); diff --git a/core/java/android/companion/ISystemDataTransferCallback.aidl b/core/java/android/companion/ISystemDataTransferCallback.aidl new file mode 100644 index 0000000000000..1ae5376942e25 --- /dev/null +++ b/core/java/android/companion/ISystemDataTransferCallback.aidl @@ -0,0 +1,24 @@ +/* + * 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 per missions and + * limitations under the License. + */ + +package android.companion; + +/** @hide */ +interface ISystemDataTransferCallback { + oneway void onResult(); + + oneway void onError(String error); +} \ No newline at end of file diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java index c7bd3a7c18aa2..995df3fb03242 100644 --- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java @@ -62,6 +62,7 @@ import android.companion.DeviceNotAssociatedException; import android.companion.IAssociationRequestCallback; import android.companion.ICompanionDeviceManager; import android.companion.IOnAssociationsChangedListener; +import android.companion.ISystemDataTransferCallback; import android.content.ComponentName; import android.content.Context; import android.content.SharedPreferences; @@ -722,9 +723,10 @@ public class CompanionDeviceManagerService extends SystemService { } @Override - public void startSystemDataTransfer(String packageName, int userId, int associationId) { + public void startSystemDataTransfer(String packageName, int userId, int associationId, + ISystemDataTransferCallback callback) { mSystemDataTransferProcessor.startSystemDataTransfer(packageName, userId, - associationId); + associationId, callback); } @Override diff --git a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java index a839492dd7ac1..7eede552ac712 100644 --- a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java +++ b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java @@ -29,6 +29,7 @@ import android.annotation.UserIdInt; import android.app.PendingIntent; import android.companion.AssociationInfo; import android.companion.DeviceNotAssociatedException; +import android.companion.ISystemDataTransferCallback; import android.companion.datatransfer.PermissionSyncRequest; import android.companion.datatransfer.SystemDataTransferRequest; import android.content.ComponentName; @@ -167,8 +168,11 @@ public class SystemDataTransferProcessor { /** * Start system data transfer. It should first try to establish a secure channel and then sync * system data. + * + * TODO: execute callback when the transfer finishes successfully or with errors. */ - public void startSystemDataTransfer(String packageName, int userId, int associationId) { + public void startSystemDataTransfer(String packageName, int userId, int associationId, + ISystemDataTransferCallback callback) { Slog.i(LOG_TAG, "Start system data transfer for package [" + packageName + "] userId [" + userId + "] associationId [" + associationId + "]");