Loading core/api/system-current.txt +3 −0 Original line number Diff line number Diff line Loading @@ -3153,7 +3153,9 @@ package android.app.wearable { public class WearableSensingManager { method @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void provideData(@NonNull android.os.PersistableBundle, @Nullable android.os.SharedMemory, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); method @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void provideDataStream(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); method @FlaggedApi("android.app.wearable.enable_provide_wearable_connection_api") @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void provideWearableConnection(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); field public static final int STATUS_ACCESS_DENIED = 5; // 0x5 field @FlaggedApi("android.app.wearable.enable_provide_wearable_connection_api") public static final int STATUS_CHANNEL_ERROR = 7; // 0x7 field public static final int STATUS_SERVICE_UNAVAILABLE = 3; // 0x3 field public static final int STATUS_SUCCESS = 1; // 0x1 field public static final int STATUS_UNKNOWN = 0; // 0x0 Loading Loading @@ -13429,6 +13431,7 @@ package android.service.wearable { method @BinderThread public abstract void onDataProvided(@NonNull android.os.PersistableBundle, @Nullable android.os.SharedMemory, @NonNull java.util.function.Consumer<java.lang.Integer>); method @BinderThread public abstract void onDataStreamProvided(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.function.Consumer<java.lang.Integer>); method @BinderThread public abstract void onQueryServiceStatus(@NonNull java.util.Set<java.lang.Integer>, @NonNull String, @NonNull java.util.function.Consumer<android.service.ambientcontext.AmbientContextDetectionServiceStatus>); method @FlaggedApi("android.app.wearable.enable_provide_wearable_connection_api") @BinderThread public void onSecureWearableConnectionProvided(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.function.Consumer<java.lang.Integer>); method @BinderThread public abstract void onStartDetection(@NonNull android.app.ambientcontext.AmbientContextEventRequest, @NonNull String, @NonNull java.util.function.Consumer<android.service.ambientcontext.AmbientContextDetectionServiceStatus>, @NonNull java.util.function.Consumer<android.service.ambientcontext.AmbientContextDetectionResult>); method public abstract void onStopDetection(@NonNull String); field public static final String SERVICE_INTERFACE = "android.service.wearable.WearableSensingService"; core/java/android/app/wearable/IWearableSensingManager.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,8 @@ import android.os.SharedMemory; * @hide */ interface IWearableSensingManager { @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE)") void provideWearableConnection(in ParcelFileDescriptor parcelFileDescriptor, in RemoteCallback callback); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE)") void provideDataStream(in ParcelFileDescriptor parcelFileDescriptor, in RemoteCallback callback); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE)") Loading core/java/android/app/wearable/WearableSensingManager.java +82 −19 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.app.ambientcontext.AmbientContextEvent; import android.companion.CompanionDeviceManager; import android.content.Context; import android.os.Binder; import android.os.ParcelFileDescriptor; Loading @@ -36,6 +37,8 @@ import android.os.SharedMemory; import android.service.wearable.WearableSensingService; import android.system.OsConstants; import java.io.InputStream; import java.io.OutputStream; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.concurrent.Executor; Loading Loading @@ -107,6 +110,14 @@ public class WearableSensingManager { @FlaggedApi(Flags.FLAG_ENABLE_UNSUPPORTED_OPERATION_STATUS_CODE) public static final int STATUS_UNSUPPORTED_OPERATION = 6; /** * The value of the status code that indicates an error occurred in the encrypted channel backed * by the provided connection. See {@link #provideWearableConnection(ParcelFileDescriptor, * Executor, Consumer)}. */ @FlaggedApi(Flags.FLAG_ENABLE_PROVIDE_WEARABLE_CONNECTION_API) public static final int STATUS_CHANNEL_ERROR = 7; /** @hide */ @IntDef(prefix = { "STATUS_" }, value = { STATUS_UNKNOWN, Loading @@ -115,7 +126,8 @@ public class WearableSensingManager { STATUS_SERVICE_UNAVAILABLE, STATUS_WEARABLE_UNAVAILABLE, STATUS_ACCESS_DENIED, STATUS_UNSUPPORTED_OPERATION STATUS_UNSUPPORTED_OPERATION, STATUS_CHANNEL_ERROR }) @Retention(RetentionPolicy.SOURCE) public @interface StatusCode {} Loading @@ -131,6 +143,60 @@ public class WearableSensingManager { mService = service; } /** * Provides a remote wearable device connection to the WearableSensingService and sends the * resulting status to the {@code statusConsumer} after the call. * * <p>This is used by applications that will also provide an implementation of the isolated * WearableSensingService. * * <p>The provided {@code wearableConnection} is expected to be a connection to a remotely * connected wearable device. This {@code wearableConnection} will be attached to * CompanionDeviceManager via {@link CompanionDeviceManager#attachSystemDataTransport(int, * InputStream, OutputStream)}, which will create an encrypted channel using {@code * wearableConnection} as the raw underlying connection. The wearable device is expected to * attach its side of the raw connection to its CompanionDeviceManager via the same method so * that the two CompanionDeviceManagers on the two devices can perform attestation and set up * the encrypted channel. Attestation requirements are listed in * com.android.server.security.AttestationVerificationPeerDeviceVerifier * * <p>A proxy to the encrypted channel will be provided to the WearableSensingService, which is * referred to as the secureWearableConnection in WearableSensingService. Any data written to * secureWearableConnection will be encrypted by CompanionDeviceManager and sent over the raw * {@code wearableConnection} to the remote wearable device, which is expected to use its * CompanionDeviceManager to decrypt the data. Encrypted data arriving at the raw {@code * wearableConnection} will be decrypted by CompanionDeviceManager and be readable as plain text * from secureWearableConnection. The raw {@code wearableConnection} provided to this method * will not be directly available to the WearableSensingService. * * <p>If an error occurred in the encrypted channel (such as the underlying stream closed), the * system will send a status code of {@link STATUS_CHANNEL_ERROR} to the {@code statusConsumer} * and kill the WearableSensingService process. * * <p>Before providing the secureWearableConnection, the system will restart the * WearableSensingService process. Other method calls into WearableSensingService may be dropped * during the restart. The caller is responsible for ensuring other method calls are queued * until a success status is returned from the {@code statusConsumer}. * * @param wearableConnection The connection to provide * @param executor Executor on which to run the consumer callback * @param statusConsumer A consumer that handles the status codes for providing the connection * and errors in the encrypted channel. */ @RequiresPermission(Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) @FlaggedApi(Flags.FLAG_ENABLE_PROVIDE_WEARABLE_CONNECTION_API) public void provideWearableConnection( @NonNull ParcelFileDescriptor wearableConnection, @NonNull @CallbackExecutor Executor executor, @NonNull @StatusCode Consumer<Integer> statusConsumer) { try { RemoteCallback callback = createStatusCallback(executor, statusConsumer); mService.provideWearableConnection(wearableConnection, callback); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Provides a data stream to the WearableSensingService that's backed by the * parcelFileDescriptor, and sends the result to the {@link Consumer} right after the call. Loading @@ -149,15 +215,7 @@ public class WearableSensingManager { @NonNull @CallbackExecutor Executor executor, @NonNull @StatusCode Consumer<Integer> statusConsumer) { try { RemoteCallback callback = new RemoteCallback(result -> { int status = result.getInt(STATUS_RESPONSE_BUNDLE_KEY); final long identity = Binder.clearCallingIdentity(); try { executor.execute(() -> statusConsumer.accept(status)); } finally { Binder.restoreCallingIdentity(identity); } }); RemoteCallback callback = createStatusCallback(executor, statusConsumer); mService.provideDataStream(parcelFileDescriptor, callback); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); Loading Loading @@ -191,7 +249,17 @@ public class WearableSensingManager { @NonNull @CallbackExecutor Executor executor, @NonNull @StatusCode Consumer<Integer> statusConsumer) { try { RemoteCallback callback = new RemoteCallback(result -> { RemoteCallback callback = createStatusCallback(executor, statusConsumer); mService.provideData(data, sharedMemory, callback); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } private static RemoteCallback createStatusCallback( Executor executor, Consumer<Integer> statusConsumer) { return new RemoteCallback( result -> { int status = result.getInt(STATUS_RESPONSE_BUNDLE_KEY); final long identity = Binder.clearCallingIdentity(); try { Loading @@ -200,10 +268,5 @@ public class WearableSensingManager { Binder.restoreCallingIdentity(identity); } }); mService.provideData(data, sharedMemory, callback); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } core/java/android/service/wearable/IWearableSensingService.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import android.os.SharedMemory; * @hide */ oneway interface IWearableSensingService { void provideSecureWearableConnection(in ParcelFileDescriptor parcelFileDescriptor, in RemoteCallback callback); void provideDataStream(in ParcelFileDescriptor parcelFileDescriptor, in RemoteCallback callback); void provideData(in PersistableBundle data, in SharedMemory sharedMemory, in RemoteCallback callback); void startDetection(in AmbientContextEventRequest request, in String packageName, Loading core/java/android/service/wearable/WearableSensingService.java +83 −41 Original line number Diff line number Diff line Loading @@ -17,12 +17,14 @@ package android.service.wearable; import android.annotation.BinderThread; import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.app.Service; import android.app.ambientcontext.AmbientContextEvent; import android.app.ambientcontext.AmbientContextEventRequest; import android.app.wearable.Flags; import android.app.wearable.WearableSensingManager; import android.content.Intent; import android.os.Bundle; Loading @@ -39,6 +41,7 @@ import java.util.Arrays; import java.util.HashSet; import java.util.Objects; import java.util.Set; import java.util.concurrent.Executor; import java.util.function.Consumer; /** Loading Loading @@ -92,19 +95,22 @@ public abstract class WearableSensingService extends Service { public final IBinder onBind(@NonNull Intent intent) { if (SERVICE_INTERFACE.equals(intent.getAction())) { return new IWearableSensingService.Stub() { /** {@inheritDoc} */ @Override public void provideSecureWearableConnection( ParcelFileDescriptor secureWearableConnection, RemoteCallback callback) { Objects.requireNonNull(secureWearableConnection); Consumer<Integer> consumer = createWearableStatusConsumer(callback); WearableSensingService.this.onSecureWearableConnectionProvided( secureWearableConnection, consumer); } /** {@inheritDoc} */ @Override public void provideDataStream( ParcelFileDescriptor parcelFileDescriptor, RemoteCallback callback) { ParcelFileDescriptor parcelFileDescriptor, RemoteCallback callback) { Objects.requireNonNull(parcelFileDescriptor); Consumer<Integer> consumer = response -> { Bundle bundle = new Bundle(); bundle.putInt( STATUS_RESPONSE_BUNDLE_KEY, response); callback.sendResult(bundle); }; Consumer<Integer> consumer = createWearableStatusConsumer(callback); WearableSensingService.this.onDataStreamProvided( parcelFileDescriptor, consumer); } Loading @@ -116,35 +122,35 @@ public abstract class WearableSensingService extends Service { SharedMemory sharedMemory, RemoteCallback callback) { Objects.requireNonNull(data); Consumer<Integer> consumer = response -> { Bundle bundle = new Bundle(); bundle.putInt( STATUS_RESPONSE_BUNDLE_KEY, response); callback.sendResult(bundle); }; Consumer<Integer> consumer = createWearableStatusConsumer(callback); WearableSensingService.this.onDataProvided(data, sharedMemory, consumer); } /** {@inheritDoc} */ @Override public void startDetection(@NonNull AmbientContextEventRequest request, String packageName, RemoteCallback detectionResultCallback, public void startDetection( @NonNull AmbientContextEventRequest request, String packageName, RemoteCallback detectionResultCallback, RemoteCallback statusCallback) { Objects.requireNonNull(request); Objects.requireNonNull(packageName); Objects.requireNonNull(detectionResultCallback); Objects.requireNonNull(statusCallback); Consumer<AmbientContextDetectionResult> detectionResultConsumer = result -> { Consumer<AmbientContextDetectionResult> detectionResultConsumer = result -> { Bundle bundle = new Bundle(); bundle.putParcelable( AmbientContextDetectionResult.RESULT_RESPONSE_BUNDLE_KEY, result); AmbientContextDetectionResult.RESULT_RESPONSE_BUNDLE_KEY, result); detectionResultCallback.sendResult(bundle); }; Consumer<AmbientContextDetectionServiceStatus> statusConsumer = status -> { Consumer<AmbientContextDetectionServiceStatus> statusConsumer = status -> { Bundle bundle = new Bundle(); bundle.putParcelable( AmbientContextDetectionServiceStatus.STATUS_RESPONSE_BUNDLE_KEY, AmbientContextDetectionServiceStatus .STATUS_RESPONSE_BUNDLE_KEY, status); statusCallback.sendResult(bundle); }; Loading @@ -162,15 +168,19 @@ public abstract class WearableSensingService extends Service { /** {@inheritDoc} */ @Override public void queryServiceStatus(@AmbientContextEvent.EventCode int[] eventTypes, String packageName, RemoteCallback callback) { public void queryServiceStatus( @AmbientContextEvent.EventCode int[] eventTypes, String packageName, RemoteCallback callback) { Objects.requireNonNull(eventTypes); Objects.requireNonNull(packageName); Objects.requireNonNull(callback); Consumer<AmbientContextDetectionServiceStatus> consumer = response -> { Consumer<AmbientContextDetectionServiceStatus> consumer = response -> { Bundle bundle = new Bundle(); bundle.putParcelable( AmbientContextDetectionServiceStatus.STATUS_RESPONSE_BUNDLE_KEY, AmbientContextDetectionServiceStatus .STATUS_RESPONSE_BUNDLE_KEY, response); callback.sendResult(bundle); }; Loading @@ -178,13 +188,36 @@ public abstract class WearableSensingService extends Service { WearableSensingService.this.onQueryServiceStatus( new HashSet<>(Arrays.asList(events)), packageName, consumer); } }; } Slog.w(TAG, "Incorrect service interface, returning null."); return null; } /** * Called when a secure connection to the wearable is available. See {@link * WearableSensingManager#provideWearableConnection(ParcelFileDescriptor, Executor, Consumer)} * for details about the secure connection. * * <p>When the {@code secureWearableConnection} is closed, the system will send a {@link * WearableSensingManager#STATUS_CHANNEL_ERROR} status code to the status consumer provided by * the caller of {@link WearableSensingManager#provideWearableConnection(ParcelFileDescriptor, * Executor, Consumer)}. * * <p>The implementing class should override this method. It should return an appropriate status * code via {@code statusConsumer} after receiving the {@code secureWearableConnection}. * * @param secureWearableConnection The secure connection to the wearable. * @param statusConsumer The consumer for the service status. */ @FlaggedApi(Flags.FLAG_ENABLE_PROVIDE_WEARABLE_CONNECTION_API) @BinderThread public void onSecureWearableConnectionProvided( @NonNull ParcelFileDescriptor secureWearableConnection, @NonNull Consumer<Integer> statusConsumer) { statusConsumer.accept(WearableSensingManager.STATUS_UNSUPPORTED_OPERATION); } /** * Called when a data stream to the wearable is provided. This data stream can be used to obtain * data from a wearable device. It is up to the implementation to maintain the data stream and Loading Loading @@ -275,4 +308,13 @@ public abstract class WearableSensingService extends Service { } return intArray; } @NonNull private static Consumer<Integer> createWearableStatusConsumer(RemoteCallback statusCallback) { return response -> { Bundle bundle = new Bundle(); bundle.putInt(STATUS_RESPONSE_BUNDLE_KEY, response); statusCallback.sendResult(bundle); }; } } Loading
core/api/system-current.txt +3 −0 Original line number Diff line number Diff line Loading @@ -3153,7 +3153,9 @@ package android.app.wearable { public class WearableSensingManager { method @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void provideData(@NonNull android.os.PersistableBundle, @Nullable android.os.SharedMemory, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); method @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void provideDataStream(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); method @FlaggedApi("android.app.wearable.enable_provide_wearable_connection_api") @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void provideWearableConnection(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); field public static final int STATUS_ACCESS_DENIED = 5; // 0x5 field @FlaggedApi("android.app.wearable.enable_provide_wearable_connection_api") public static final int STATUS_CHANNEL_ERROR = 7; // 0x7 field public static final int STATUS_SERVICE_UNAVAILABLE = 3; // 0x3 field public static final int STATUS_SUCCESS = 1; // 0x1 field public static final int STATUS_UNKNOWN = 0; // 0x0 Loading Loading @@ -13429,6 +13431,7 @@ package android.service.wearable { method @BinderThread public abstract void onDataProvided(@NonNull android.os.PersistableBundle, @Nullable android.os.SharedMemory, @NonNull java.util.function.Consumer<java.lang.Integer>); method @BinderThread public abstract void onDataStreamProvided(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.function.Consumer<java.lang.Integer>); method @BinderThread public abstract void onQueryServiceStatus(@NonNull java.util.Set<java.lang.Integer>, @NonNull String, @NonNull java.util.function.Consumer<android.service.ambientcontext.AmbientContextDetectionServiceStatus>); method @FlaggedApi("android.app.wearable.enable_provide_wearable_connection_api") @BinderThread public void onSecureWearableConnectionProvided(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.function.Consumer<java.lang.Integer>); method @BinderThread public abstract void onStartDetection(@NonNull android.app.ambientcontext.AmbientContextEventRequest, @NonNull String, @NonNull java.util.function.Consumer<android.service.ambientcontext.AmbientContextDetectionServiceStatus>, @NonNull java.util.function.Consumer<android.service.ambientcontext.AmbientContextDetectionResult>); method public abstract void onStopDetection(@NonNull String); field public static final String SERVICE_INTERFACE = "android.service.wearable.WearableSensingService";
core/java/android/app/wearable/IWearableSensingManager.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,8 @@ import android.os.SharedMemory; * @hide */ interface IWearableSensingManager { @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE)") void provideWearableConnection(in ParcelFileDescriptor parcelFileDescriptor, in RemoteCallback callback); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE)") void provideDataStream(in ParcelFileDescriptor parcelFileDescriptor, in RemoteCallback callback); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE)") Loading
core/java/android/app/wearable/WearableSensingManager.java +82 −19 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.app.ambientcontext.AmbientContextEvent; import android.companion.CompanionDeviceManager; import android.content.Context; import android.os.Binder; import android.os.ParcelFileDescriptor; Loading @@ -36,6 +37,8 @@ import android.os.SharedMemory; import android.service.wearable.WearableSensingService; import android.system.OsConstants; import java.io.InputStream; import java.io.OutputStream; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.concurrent.Executor; Loading Loading @@ -107,6 +110,14 @@ public class WearableSensingManager { @FlaggedApi(Flags.FLAG_ENABLE_UNSUPPORTED_OPERATION_STATUS_CODE) public static final int STATUS_UNSUPPORTED_OPERATION = 6; /** * The value of the status code that indicates an error occurred in the encrypted channel backed * by the provided connection. See {@link #provideWearableConnection(ParcelFileDescriptor, * Executor, Consumer)}. */ @FlaggedApi(Flags.FLAG_ENABLE_PROVIDE_WEARABLE_CONNECTION_API) public static final int STATUS_CHANNEL_ERROR = 7; /** @hide */ @IntDef(prefix = { "STATUS_" }, value = { STATUS_UNKNOWN, Loading @@ -115,7 +126,8 @@ public class WearableSensingManager { STATUS_SERVICE_UNAVAILABLE, STATUS_WEARABLE_UNAVAILABLE, STATUS_ACCESS_DENIED, STATUS_UNSUPPORTED_OPERATION STATUS_UNSUPPORTED_OPERATION, STATUS_CHANNEL_ERROR }) @Retention(RetentionPolicy.SOURCE) public @interface StatusCode {} Loading @@ -131,6 +143,60 @@ public class WearableSensingManager { mService = service; } /** * Provides a remote wearable device connection to the WearableSensingService and sends the * resulting status to the {@code statusConsumer} after the call. * * <p>This is used by applications that will also provide an implementation of the isolated * WearableSensingService. * * <p>The provided {@code wearableConnection} is expected to be a connection to a remotely * connected wearable device. This {@code wearableConnection} will be attached to * CompanionDeviceManager via {@link CompanionDeviceManager#attachSystemDataTransport(int, * InputStream, OutputStream)}, which will create an encrypted channel using {@code * wearableConnection} as the raw underlying connection. The wearable device is expected to * attach its side of the raw connection to its CompanionDeviceManager via the same method so * that the two CompanionDeviceManagers on the two devices can perform attestation and set up * the encrypted channel. Attestation requirements are listed in * com.android.server.security.AttestationVerificationPeerDeviceVerifier * * <p>A proxy to the encrypted channel will be provided to the WearableSensingService, which is * referred to as the secureWearableConnection in WearableSensingService. Any data written to * secureWearableConnection will be encrypted by CompanionDeviceManager and sent over the raw * {@code wearableConnection} to the remote wearable device, which is expected to use its * CompanionDeviceManager to decrypt the data. Encrypted data arriving at the raw {@code * wearableConnection} will be decrypted by CompanionDeviceManager and be readable as plain text * from secureWearableConnection. The raw {@code wearableConnection} provided to this method * will not be directly available to the WearableSensingService. * * <p>If an error occurred in the encrypted channel (such as the underlying stream closed), the * system will send a status code of {@link STATUS_CHANNEL_ERROR} to the {@code statusConsumer} * and kill the WearableSensingService process. * * <p>Before providing the secureWearableConnection, the system will restart the * WearableSensingService process. Other method calls into WearableSensingService may be dropped * during the restart. The caller is responsible for ensuring other method calls are queued * until a success status is returned from the {@code statusConsumer}. * * @param wearableConnection The connection to provide * @param executor Executor on which to run the consumer callback * @param statusConsumer A consumer that handles the status codes for providing the connection * and errors in the encrypted channel. */ @RequiresPermission(Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) @FlaggedApi(Flags.FLAG_ENABLE_PROVIDE_WEARABLE_CONNECTION_API) public void provideWearableConnection( @NonNull ParcelFileDescriptor wearableConnection, @NonNull @CallbackExecutor Executor executor, @NonNull @StatusCode Consumer<Integer> statusConsumer) { try { RemoteCallback callback = createStatusCallback(executor, statusConsumer); mService.provideWearableConnection(wearableConnection, callback); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Provides a data stream to the WearableSensingService that's backed by the * parcelFileDescriptor, and sends the result to the {@link Consumer} right after the call. Loading @@ -149,15 +215,7 @@ public class WearableSensingManager { @NonNull @CallbackExecutor Executor executor, @NonNull @StatusCode Consumer<Integer> statusConsumer) { try { RemoteCallback callback = new RemoteCallback(result -> { int status = result.getInt(STATUS_RESPONSE_BUNDLE_KEY); final long identity = Binder.clearCallingIdentity(); try { executor.execute(() -> statusConsumer.accept(status)); } finally { Binder.restoreCallingIdentity(identity); } }); RemoteCallback callback = createStatusCallback(executor, statusConsumer); mService.provideDataStream(parcelFileDescriptor, callback); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); Loading Loading @@ -191,7 +249,17 @@ public class WearableSensingManager { @NonNull @CallbackExecutor Executor executor, @NonNull @StatusCode Consumer<Integer> statusConsumer) { try { RemoteCallback callback = new RemoteCallback(result -> { RemoteCallback callback = createStatusCallback(executor, statusConsumer); mService.provideData(data, sharedMemory, callback); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } private static RemoteCallback createStatusCallback( Executor executor, Consumer<Integer> statusConsumer) { return new RemoteCallback( result -> { int status = result.getInt(STATUS_RESPONSE_BUNDLE_KEY); final long identity = Binder.clearCallingIdentity(); try { Loading @@ -200,10 +268,5 @@ public class WearableSensingManager { Binder.restoreCallingIdentity(identity); } }); mService.provideData(data, sharedMemory, callback); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } }
core/java/android/service/wearable/IWearableSensingService.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import android.os.SharedMemory; * @hide */ oneway interface IWearableSensingService { void provideSecureWearableConnection(in ParcelFileDescriptor parcelFileDescriptor, in RemoteCallback callback); void provideDataStream(in ParcelFileDescriptor parcelFileDescriptor, in RemoteCallback callback); void provideData(in PersistableBundle data, in SharedMemory sharedMemory, in RemoteCallback callback); void startDetection(in AmbientContextEventRequest request, in String packageName, Loading
core/java/android/service/wearable/WearableSensingService.java +83 −41 Original line number Diff line number Diff line Loading @@ -17,12 +17,14 @@ package android.service.wearable; import android.annotation.BinderThread; import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.app.Service; import android.app.ambientcontext.AmbientContextEvent; import android.app.ambientcontext.AmbientContextEventRequest; import android.app.wearable.Flags; import android.app.wearable.WearableSensingManager; import android.content.Intent; import android.os.Bundle; Loading @@ -39,6 +41,7 @@ import java.util.Arrays; import java.util.HashSet; import java.util.Objects; import java.util.Set; import java.util.concurrent.Executor; import java.util.function.Consumer; /** Loading Loading @@ -92,19 +95,22 @@ public abstract class WearableSensingService extends Service { public final IBinder onBind(@NonNull Intent intent) { if (SERVICE_INTERFACE.equals(intent.getAction())) { return new IWearableSensingService.Stub() { /** {@inheritDoc} */ @Override public void provideSecureWearableConnection( ParcelFileDescriptor secureWearableConnection, RemoteCallback callback) { Objects.requireNonNull(secureWearableConnection); Consumer<Integer> consumer = createWearableStatusConsumer(callback); WearableSensingService.this.onSecureWearableConnectionProvided( secureWearableConnection, consumer); } /** {@inheritDoc} */ @Override public void provideDataStream( ParcelFileDescriptor parcelFileDescriptor, RemoteCallback callback) { ParcelFileDescriptor parcelFileDescriptor, RemoteCallback callback) { Objects.requireNonNull(parcelFileDescriptor); Consumer<Integer> consumer = response -> { Bundle bundle = new Bundle(); bundle.putInt( STATUS_RESPONSE_BUNDLE_KEY, response); callback.sendResult(bundle); }; Consumer<Integer> consumer = createWearableStatusConsumer(callback); WearableSensingService.this.onDataStreamProvided( parcelFileDescriptor, consumer); } Loading @@ -116,35 +122,35 @@ public abstract class WearableSensingService extends Service { SharedMemory sharedMemory, RemoteCallback callback) { Objects.requireNonNull(data); Consumer<Integer> consumer = response -> { Bundle bundle = new Bundle(); bundle.putInt( STATUS_RESPONSE_BUNDLE_KEY, response); callback.sendResult(bundle); }; Consumer<Integer> consumer = createWearableStatusConsumer(callback); WearableSensingService.this.onDataProvided(data, sharedMemory, consumer); } /** {@inheritDoc} */ @Override public void startDetection(@NonNull AmbientContextEventRequest request, String packageName, RemoteCallback detectionResultCallback, public void startDetection( @NonNull AmbientContextEventRequest request, String packageName, RemoteCallback detectionResultCallback, RemoteCallback statusCallback) { Objects.requireNonNull(request); Objects.requireNonNull(packageName); Objects.requireNonNull(detectionResultCallback); Objects.requireNonNull(statusCallback); Consumer<AmbientContextDetectionResult> detectionResultConsumer = result -> { Consumer<AmbientContextDetectionResult> detectionResultConsumer = result -> { Bundle bundle = new Bundle(); bundle.putParcelable( AmbientContextDetectionResult.RESULT_RESPONSE_BUNDLE_KEY, result); AmbientContextDetectionResult.RESULT_RESPONSE_BUNDLE_KEY, result); detectionResultCallback.sendResult(bundle); }; Consumer<AmbientContextDetectionServiceStatus> statusConsumer = status -> { Consumer<AmbientContextDetectionServiceStatus> statusConsumer = status -> { Bundle bundle = new Bundle(); bundle.putParcelable( AmbientContextDetectionServiceStatus.STATUS_RESPONSE_BUNDLE_KEY, AmbientContextDetectionServiceStatus .STATUS_RESPONSE_BUNDLE_KEY, status); statusCallback.sendResult(bundle); }; Loading @@ -162,15 +168,19 @@ public abstract class WearableSensingService extends Service { /** {@inheritDoc} */ @Override public void queryServiceStatus(@AmbientContextEvent.EventCode int[] eventTypes, String packageName, RemoteCallback callback) { public void queryServiceStatus( @AmbientContextEvent.EventCode int[] eventTypes, String packageName, RemoteCallback callback) { Objects.requireNonNull(eventTypes); Objects.requireNonNull(packageName); Objects.requireNonNull(callback); Consumer<AmbientContextDetectionServiceStatus> consumer = response -> { Consumer<AmbientContextDetectionServiceStatus> consumer = response -> { Bundle bundle = new Bundle(); bundle.putParcelable( AmbientContextDetectionServiceStatus.STATUS_RESPONSE_BUNDLE_KEY, AmbientContextDetectionServiceStatus .STATUS_RESPONSE_BUNDLE_KEY, response); callback.sendResult(bundle); }; Loading @@ -178,13 +188,36 @@ public abstract class WearableSensingService extends Service { WearableSensingService.this.onQueryServiceStatus( new HashSet<>(Arrays.asList(events)), packageName, consumer); } }; } Slog.w(TAG, "Incorrect service interface, returning null."); return null; } /** * Called when a secure connection to the wearable is available. See {@link * WearableSensingManager#provideWearableConnection(ParcelFileDescriptor, Executor, Consumer)} * for details about the secure connection. * * <p>When the {@code secureWearableConnection} is closed, the system will send a {@link * WearableSensingManager#STATUS_CHANNEL_ERROR} status code to the status consumer provided by * the caller of {@link WearableSensingManager#provideWearableConnection(ParcelFileDescriptor, * Executor, Consumer)}. * * <p>The implementing class should override this method. It should return an appropriate status * code via {@code statusConsumer} after receiving the {@code secureWearableConnection}. * * @param secureWearableConnection The secure connection to the wearable. * @param statusConsumer The consumer for the service status. */ @FlaggedApi(Flags.FLAG_ENABLE_PROVIDE_WEARABLE_CONNECTION_API) @BinderThread public void onSecureWearableConnectionProvided( @NonNull ParcelFileDescriptor secureWearableConnection, @NonNull Consumer<Integer> statusConsumer) { statusConsumer.accept(WearableSensingManager.STATUS_UNSUPPORTED_OPERATION); } /** * Called when a data stream to the wearable is provided. This data stream can be used to obtain * data from a wearable device. It is up to the implementation to maintain the data stream and Loading Loading @@ -275,4 +308,13 @@ public abstract class WearableSensingService extends Service { } return intArray; } @NonNull private static Consumer<Integer> createWearableStatusConsumer(RemoteCallback statusCallback) { return response -> { Bundle bundle = new Bundle(); bundle.putInt(STATUS_RESPONSE_BUNDLE_KEY, response); statusCallback.sendResult(bundle); }; } }