From 8ef76e4ce3973d005dd9473092d8cc222fd9cad4 Mon Sep 17 00:00:00 2001 From: Guojing Yuan Date: Tue, 3 Jan 2023 23:25:43 +0000 Subject: [PATCH] Add an API to set if ContextSync is enabled Allow companion apps to control whether ContextSync is enabled. By default it's opted-in/enabled. Bug: 261885804 Test: CTS tests Change-Id: Ib77726a441435511ae87c0e4f9f73c421c1c7acf --- core/api/current.txt | 4 + .../android/companion/AssociationInfo.java | 78 ++++++++++--------- .../companion/CompanionDeviceManager.java | 56 +++++++++++++ .../companion/ICompanionDeviceManager.aidl | 4 + .../AssociationRequestsProcessor.java | 23 +++++- .../CompanionDeviceManagerService.java | 12 +++ .../server/companion/PersistentDataStore.java | 19 +++-- .../VirtualDeviceManagerServiceTest.java | 2 +- 8 files changed, 152 insertions(+), 46 deletions(-) diff --git a/core/api/current.txt b/core/api/current.txt index 84274cb507674..c21d56d4a36a7 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -9178,6 +9178,7 @@ package android.companion { method @Nullable public String getDeviceProfile(); method @Nullable public CharSequence getDisplayName(); method public int getId(); + method public int getSystemDataSyncFlags(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator CREATOR; } @@ -9247,8 +9248,10 @@ package android.companion { method @RequiresPermission(anyOf={android.Manifest.permission.REQUEST_COMPANION_PROFILE_WATCH, android.Manifest.permission.REQUEST_COMPANION_PROFILE_COMPUTER, android.Manifest.permission.REQUEST_COMPANION_PROFILE_APP_STREAMING, android.Manifest.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION}, conditional=true) public void associate(@NonNull android.companion.AssociationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.companion.CompanionDeviceManager.Callback); method @Nullable public android.content.IntentSender buildAssociationCancellationIntent(); method @Nullable public android.content.IntentSender buildPermissionTransferUserConsentIntent(int) throws android.companion.DeviceNotAssociatedException; + method public void disableSystemDataSync(int, int); method @Deprecated public void disassociate(@NonNull String); method public void disassociate(int); + method public void enableSystemDataSync(int, int); method @NonNull @RequiresPermission("android.permission.MANAGE_COMPANION_DEVICES") public java.util.List getAllAssociations(); method @Deprecated @NonNull public java.util.List getAssociations(); method @NonNull public java.util.List getMyAssociations(); @@ -9259,6 +9262,7 @@ package android.companion { 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"; + field public static final int FLAG_CALL_METADATA = 1; // 0x1 field public static final int RESULT_CANCELED = 0; // 0x0 field public static final int RESULT_DISCOVERY_TIMEOUT = 2; // 0x2 field public static final int RESULT_INTERNAL_ERROR = 3; // 0x3 diff --git a/core/java/android/companion/AssociationInfo.java b/core/java/android/companion/AssociationInfo.java index 5fd39feceb23b..0958a806a5ff5 100644 --- a/core/java/android/companion/AssociationInfo.java +++ b/core/java/android/companion/AssociationInfo.java @@ -56,6 +56,7 @@ public final class AssociationInfo implements Parcelable { private final boolean mSelfManaged; private final boolean mNotifyOnDeviceNearby; + private final int mSystemDataSyncFlags; /** * Indicates that the association has been revoked (removed), but we keep the association @@ -73,7 +74,6 @@ public final class AssociationInfo implements Parcelable { /** * Creates a new Association. - * Only to be used by the CompanionDeviceManagerService. * * @hide */ @@ -81,7 +81,7 @@ public final class AssociationInfo implements Parcelable { @Nullable MacAddress macAddress, @Nullable CharSequence displayName, @Nullable String deviceProfile, @Nullable AssociatedDevice associatedDevice, boolean selfManaged, boolean notifyOnDeviceNearby, boolean revoked, - long timeApprovedMs, long lastTimeConnectedMs) { + long timeApprovedMs, long lastTimeConnectedMs, int systemDataSyncFlags) { if (id <= 0) { throw new IllegalArgumentException("Association ID should be greater than 0"); } @@ -105,6 +105,7 @@ public final class AssociationInfo implements Parcelable { mRevoked = revoked; mTimeApprovedMs = timeApprovedMs; mLastTimeConnectedMs = lastTimeConnectedMs; + mSystemDataSyncFlags = systemDataSyncFlags; } /** @@ -220,6 +221,16 @@ public final class AssociationInfo implements Parcelable { return mLastTimeConnectedMs; } + /** + * @return Enabled system data sync flags set via + * {@link CompanionDeviceManager#enableSystemDataSync(int, int)} and + * {@link CompanionDeviceManager#disableSystemDataSync(int, int)}. + * Or by default all flags are 1 (enabled). + */ + public int getSystemDataSyncFlags() { + return mSystemDataSyncFlags; + } + /** * Utility method for checking if the association represents a device with the given MAC * address. @@ -287,6 +298,7 @@ public final class AssociationInfo implements Parcelable { + ", mLastTimeConnectedMs=" + ( mLastTimeConnectedMs == Long.MAX_VALUE ? LAST_TIME_CONNECTED_NONE : new Date(mLastTimeConnectedMs)) + + ", mSystemDataSyncFlags=" + mSystemDataSyncFlags + '}'; } @@ -306,14 +318,15 @@ public final class AssociationInfo implements Parcelable { && Objects.equals(mDeviceMacAddress, that.mDeviceMacAddress) && Objects.equals(mDisplayName, that.mDisplayName) && Objects.equals(mDeviceProfile, that.mDeviceProfile) - && Objects.equals(mAssociatedDevice, that.mAssociatedDevice); + && Objects.equals(mAssociatedDevice, that.mAssociatedDevice) + && mSystemDataSyncFlags == that.mSystemDataSyncFlags; } @Override public int hashCode() { return Objects.hash(mId, mUserId, mPackageName, mDeviceMacAddress, mDisplayName, mDeviceProfile, mAssociatedDevice, mSelfManaged, mNotifyOnDeviceNearby, mRevoked, - mTimeApprovedMs, mLastTimeConnectedMs); + mTimeApprovedMs, mLastTimeConnectedMs, mSystemDataSyncFlags); } @Override @@ -338,6 +351,7 @@ public final class AssociationInfo implements Parcelable { dest.writeBoolean(mRevoked); dest.writeLong(mTimeApprovedMs); dest.writeLong(mLastTimeConnectedMs); + dest.writeInt(mSystemDataSyncFlags); } private AssociationInfo(@NonNull Parcel in) { @@ -356,6 +370,7 @@ public final class AssociationInfo implements Parcelable { mRevoked = in.readBoolean(); mTimeApprovedMs = in.readLong(); mLastTimeConnectedMs = in.readLong(); + mSystemDataSyncFlags = in.readInt(); } @NonNull @@ -390,27 +405,24 @@ public final class AssociationInfo implements Parcelable { return new Builder(info); } - /** - * @hide - */ + /** @hide */ public static final class Builder implements NonActionableBuilder { @NonNull private final AssociationInfo mOriginalInfo; private boolean mNotifyOnDeviceNearby; private boolean mRevoked; private long mLastTimeConnectedMs; + private int mSystemDataSyncFlags; private Builder(@NonNull AssociationInfo info) { mOriginalInfo = info; mNotifyOnDeviceNearby = info.mNotifyOnDeviceNearby; mRevoked = info.mRevoked; mLastTimeConnectedMs = info.mLastTimeConnectedMs; + mSystemDataSyncFlags = info.mSystemDataSyncFlags; } - /** - * Should only be used by the CompanionDeviceManagerService. - * @hide - */ + /** @hide */ @Override @NonNull public Builder setLastTimeConnected(long lastTimeConnectedMs) { @@ -423,10 +435,7 @@ public final class AssociationInfo implements Parcelable { return this; } - /** - * Should only be used by the CompanionDeviceManagerService. - * @hide - */ + /** @hide */ @Override @NonNull public Builder setNotifyOnDeviceNearby(boolean notifyOnDeviceNearby) { @@ -434,10 +443,7 @@ public final class AssociationInfo implements Parcelable { return this; } - /** - * Should only be used by the CompanionDeviceManagerService. - * @hide - */ + /** @hide */ @Override @NonNull public Builder setRevoked(boolean revoked) { @@ -445,9 +451,15 @@ public final class AssociationInfo implements Parcelable { return this; } - /** - * @hide - */ + /** @hide */ + @Override + @NonNull + public Builder setSystemDataSyncFlags(int flags) { + mSystemDataSyncFlags = flags; + return this; + } + + /** @hide */ @NonNull public AssociationInfo build() { return new AssociationInfo( @@ -462,7 +474,8 @@ public final class AssociationInfo implements Parcelable { mNotifyOnDeviceNearby, mRevoked, mOriginalInfo.mTimeApprovedMs, - mLastTimeConnectedMs + mLastTimeConnectedMs, + mSystemDataSyncFlags ); } } @@ -480,25 +493,20 @@ public final class AssociationInfo implements Parcelable { * @hide */ public interface NonActionableBuilder { - /** - * Should only be used by the CompanionDeviceManagerService. - * @hide - */ + /** @hide */ @NonNull Builder setNotifyOnDeviceNearby(boolean notifyOnDeviceNearby); - /** - * Should only be used by the CompanionDeviceManagerService. - * @hide - */ + /** @hide */ @NonNull Builder setLastTimeConnected(long lastTimeConnectedMs); - /** - * Should only be used by the CompanionDeviceManagerService. - * @hide - */ + /** @hide */ @NonNull Builder setRevoked(boolean revoked); + + /** @hide */ + @NonNull + Builder setSystemDataSyncFlags(int flags); } } diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java index d31124d452a8c..baa88e41d1b79 100644 --- a/core/java/android/companion/CompanionDeviceManager.java +++ b/core/java/android/companion/CompanionDeviceManager.java @@ -166,6 +166,19 @@ public final class CompanionDeviceManager { */ public static final String REASON_CANCELED = "canceled"; + /** @hide */ + @IntDef(flag = true, prefix = { "FLAG_" }, value = { + FLAG_CALL_METADATA, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface DataSyncTypes {} + + /** + * Used by {@link #enableSystemDataSync(int, int)}}. + * Sync call metadata like muting, ending and silencing a call. + * + */ + public static final int FLAG_CALL_METADATA = 1; /** * A device, returned in the activity result of the {@link IntentSender} received in @@ -468,6 +481,49 @@ public final class CompanionDeviceManager { } } + /** + *

Enable system data sync (it only supports call metadata sync for now). + * By default all supported system data types are enabled.

+ * + *

Calling this API requires a uses-feature + * {@link PackageManager#FEATURE_COMPANION_DEVICE_SETUP} declaration in the manifest

+ * + * @param associationId id of the device association. + * @param flags system data types to be enabled. + */ + public void enableSystemDataSync(int associationId, @DataSyncTypes int flags) { + if (!checkFeaturePresent()) { + return; + } + + try { + mService.enableSystemDataSync(associationId, flags); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + *

Disable system data sync (it only supports call metadata sync for now). + * By default all supported system data types are enabled.

+ * + *

Calling this API requires a uses-feature + * {@link PackageManager#FEATURE_COMPANION_DEVICE_SETUP} declaration in the manifest

+ * + * @param associationId id of the device association. + * @param flags system data types to be disabled. + */ + public void disableSystemDataSync(int associationId, @DataSyncTypes int flags) { + if (!checkFeaturePresent()) { + return; + } + + try { + mService.disableSystemDataSync(associationId, flags); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } /** *

Calling this API requires a uses-feature diff --git a/core/java/android/companion/ICompanionDeviceManager.aidl b/core/java/android/companion/ICompanionDeviceManager.aidl index 24ef52b37dabe..010aa8f8a5040 100644 --- a/core/java/android/companion/ICompanionDeviceManager.aidl +++ b/core/java/android/companion/ICompanionDeviceManager.aidl @@ -84,4 +84,8 @@ interface ICompanionDeviceManager { boolean isCompanionApplicationBound(String packageName, int userId); PendingIntent buildAssociationCancellationIntent(in String callingPackage, int userId); + + void enableSystemDataSync(int associationId, int flags); + + void disableSystemDataSync(int associationId, int flags); } diff --git a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java index b04f3c57c2c14..e9cd84aaf0be6 100644 --- a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java +++ b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java @@ -268,9 +268,9 @@ class AssociationRequestsProcessor { @NonNull ResultReceiver resultReceiver) { final long callingIdentity = Binder.clearCallingIdentity(); try { - createAssociation(userId, packageName, macAddress, - request.getDisplayName(), request.getDeviceProfile(), - request.getAssociatedDevice(), request.isSelfManaged(), + createAssociation(userId, packageName, macAddress, request.getDisplayName(), + request.getDeviceProfile(), request.getAssociatedDevice(), + request.isSelfManaged(), callback, resultReceiver); } finally { Binder.restoreCallingIdentity(callingIdentity); @@ -287,7 +287,8 @@ class AssociationRequestsProcessor { final AssociationInfo association = new AssociationInfo(id, userId, packageName, macAddress, displayName, deviceProfile, associatedDevice, selfManaged, - /* notifyOnDeviceNearby */ false, /* revoked */ false, timestamp, Long.MAX_VALUE); + /* notifyOnDeviceNearby */ false, /* revoked */ false, timestamp, Long.MAX_VALUE, + /* systemDataSyncFlags */ ~0); if (deviceProfile != null) { // If the "Device Profile" is specified, make the companion application a holder of the @@ -315,6 +316,20 @@ class AssociationRequestsProcessor { // that there are other devices with the same profile, so the role holder won't be removed. } + public void enableSystemDataSync(int associationId, int flags) { + AssociationInfo association = mAssociationStore.getAssociationById(associationId); + AssociationInfo updated = AssociationInfo.builder(association) + .setSystemDataSyncFlags(association.getSystemDataSyncFlags() | flags).build(); + mAssociationStore.updateAssociation(updated); + } + + public void disableSystemDataSync(int associationId, int flags) { + AssociationInfo association = mAssociationStore.getAssociationById(associationId); + AssociationInfo updated = AssociationInfo.builder(association) + .setSystemDataSyncFlags(association.getSystemDataSyncFlags() & (~flags)).build(); + mAssociationStore.updateAssociation(updated); + } + private void addAssociationToStore(@NonNull AssociationInfo association, @Nullable String deviceProfile) { Slog.i(TAG, "New CDM association created=" + association); diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java index d34fc595ea5e2..d7043c5ace39b 100644 --- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java @@ -713,6 +713,18 @@ public class CompanionDeviceManagerService extends SystemService { mTransportManager.detachSystemDataTransport(packageName, userId, associationId); } + @Override + public void enableSystemDataSync(int associationId, int flags) { + getAssociationWithCallerChecks(associationId); + mAssociationRequestsProcessor.enableSystemDataSync(associationId, flags); + } + + @Override + public void disableSystemDataSync(int associationId, int flags) { + getAssociationWithCallerChecks(associationId); + mAssociationRequestsProcessor.disableSystemDataSync(associationId, flags); + } + @Override public void notifyDeviceAppeared(int associationId) { if (DEBUG) Log.i(TAG, "notifyDevice_Appeared() id=" + associationId); diff --git a/services/companion/java/com/android/server/companion/PersistentDataStore.java b/services/companion/java/com/android/server/companion/PersistentDataStore.java index a57f5a2a39326..b66c1937b8dd4 100644 --- a/services/companion/java/com/android/server/companion/PersistentDataStore.java +++ b/services/companion/java/com/android/server/companion/PersistentDataStore.java @@ -132,7 +132,8 @@ import java.util.concurrent.ConcurrentMap; * notify_device_nearby="false" * revoked="false" * last_time_connected="1634641160229" - * time_approved="1634389553216"/> + * time_approved="1634389553216" + * system_data_sync_flags="-1"/> * * + * time_approved="1634641160229" + * system_data_sync_flags="-1"/> * * * @@ -185,6 +187,7 @@ final class PersistentDataStore { private static final String XML_ATTR_REVOKED = "revoked"; private static final String XML_ATTR_TIME_APPROVED = "time_approved"; private static final String XML_ATTR_LAST_TIME_CONNECTED = "last_time_connected"; + private static final String XML_ATTR_SYSTEM_DATA_SYNC_FLAGS = "system_data_sync_flags"; private static final String LEGACY_XML_ATTR_DEVICE = "device"; @@ -429,7 +432,7 @@ final class PersistentDataStore { out.add(new AssociationInfo(associationId, userId, appPackage, MacAddress.fromString(deviceAddress), null, profile, null, /* managedByCompanionApp */ false, notify, /* revoked */ false, timeApproved, - Long.MAX_VALUE)); + Long.MAX_VALUE, /* systemDataSyncFlags */ -1)); } private static void readAssociationsV1(@NonNull TypedXmlPullParser parser, @@ -462,10 +465,12 @@ final class PersistentDataStore { final long timeApproved = readLongAttribute(parser, XML_ATTR_TIME_APPROVED, 0L); final long lastTimeConnected = readLongAttribute( parser, XML_ATTR_LAST_TIME_CONNECTED, Long.MAX_VALUE); + final int systemDataSyncFlags = readIntAttribute(parser, + XML_ATTR_SYSTEM_DATA_SYNC_FLAGS, -1); final AssociationInfo associationInfo = createAssociationInfoNoThrow(associationId, userId, appPackage, macAddress, displayName, profile, selfManaged, notify, revoked, - timeApproved, lastTimeConnected); + timeApproved, lastTimeConnected, systemDataSyncFlags); if (associationInfo != null) { out.add(associationInfo); } @@ -523,6 +528,7 @@ final class PersistentDataStore { writeLongAttribute(serializer, XML_ATTR_TIME_APPROVED, a.getTimeApprovedMs()); writeLongAttribute( serializer, XML_ATTR_LAST_TIME_CONNECTED, a.getLastTimeConnectedMs()); + writeIntAttribute(serializer, XML_ATTR_SYSTEM_DATA_SYNC_FLAGS, a.getSystemDataSyncFlags()); serializer.endTag(null, XML_TAG_ASSOCIATION); } @@ -561,14 +567,15 @@ final class PersistentDataStore { private static AssociationInfo createAssociationInfoNoThrow(int associationId, @UserIdInt int userId, @NonNull String appPackage, @Nullable MacAddress macAddress, @Nullable CharSequence displayName, @Nullable String profile, boolean selfManaged, - boolean notify, boolean revoked, long timeApproved, long lastTimeConnected) { + boolean notify, boolean revoked, long timeApproved, long lastTimeConnected, + int systemDataSyncFlags) { AssociationInfo associationInfo = null; try { // We do not persist AssociatedDevice, which means that AssociationInfo retrieved from // datastore is not guaranteed to be identical to the one from initial association. associationInfo = new AssociationInfo(associationId, userId, appPackage, macAddress, displayName, profile, null, selfManaged, notify, revoked, - timeApproved, lastTimeConnected); + timeApproved, lastTimeConnected, systemDataSyncFlags); } catch (Exception e) { if (DEBUG) Log.w(TAG, "Could not create AssociationInfo", e); } diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java index eb99e30b58eca..00d4a6dc9a8c9 100644 --- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java @@ -332,7 +332,7 @@ public class VirtualDeviceManagerServiceTest { new CameraAccessController(mContext, mLocalService, mCameraAccessBlockedCallback); mAssociationInfo = new AssociationInfo(/* associationId= */ 1, 0, null, - MacAddress.BROADCAST_ADDRESS, "", null, null, true, false, false, 0, 0); + MacAddress.BROADCAST_ADDRESS, "", null, null, true, false, false, 0, 0, -1); mVdms = new VirtualDeviceManagerService(mContext); mLocalService = mVdms.getLocalServiceInstance();