WearableSensing framework API for wearables.
WearableSensing framework APIs are intended to be used to interact and manage the WearableSensingService. The WearableSensingService provides an isolated service environment for an application to provide a remote data stream to and run sensing workloads on the data stream. Clients that want to use this API must hold the permission MANAGE_WEARABLE_SENSING_SERVICE. The permission protection level is signature|privledged. API overview: go/wearable-sensing-api Design doc: go/trusted-glasses A follow up CL will implement the integration between WearableSensingService and AmbientContextManager. A subsequent follow up will also add unit and cts testing. Bug: 244181656, 249135378 Test: Builds. Ignore-AOSP-First: to prevent new feature leak. CTS-Coverage-Bug: 259453662 Change-Id: I0c5e3c5aa01dda9d3289733abd22abfcccc15f96
This commit is contained in:
@@ -79,6 +79,7 @@ package android {
|
||||
field public static final String BIND_TRUST_AGENT = "android.permission.BIND_TRUST_AGENT";
|
||||
field public static final String BIND_TV_REMOTE_SERVICE = "android.permission.BIND_TV_REMOTE_SERVICE";
|
||||
field public static final String BIND_WALLPAPER_EFFECTS_GENERATION_SERVICE = "android.permission.BIND_WALLPAPER_EFFECTS_GENERATION_SERVICE";
|
||||
field public static final String BIND_WEARABLE_SENSING_SERVICE = "android.permission.BIND_WEARABLE_SENSING_SERVICE";
|
||||
field public static final String BLUETOOTH_MAP = "android.permission.BLUETOOTH_MAP";
|
||||
field public static final String BRICK = "android.permission.BRICK";
|
||||
field public static final String BRIGHTNESS_SLIDER_USAGE = "android.permission.BRIGHTNESS_SLIDER_USAGE";
|
||||
@@ -199,6 +200,7 @@ package android {
|
||||
field public static final String MANAGE_USER_OEM_UNLOCK_STATE = "android.permission.MANAGE_USER_OEM_UNLOCK_STATE";
|
||||
field public static final String MANAGE_WALLPAPER_EFFECTS_GENERATION = "android.permission.MANAGE_WALLPAPER_EFFECTS_GENERATION";
|
||||
field public static final String MANAGE_WEAK_ESCROW_TOKEN = "android.permission.MANAGE_WEAK_ESCROW_TOKEN";
|
||||
field public static final String MANAGE_WEARABLE_SENSING_SERVICE = "android.permission.MANAGE_WEARABLE_SENSING_SERVICE";
|
||||
field public static final String MANAGE_WIFI_COUNTRY_CODE = "android.permission.MANAGE_WIFI_COUNTRY_CODE";
|
||||
field public static final String MARK_DEVICE_ORGANIZATION_OWNED = "android.permission.MARK_DEVICE_ORGANIZATION_OWNED";
|
||||
field public static final String MEDIA_RESOURCE_OVERRIDE_PID = "android.permission.MEDIA_RESOURCE_OVERRIDE_PID";
|
||||
@@ -2825,6 +2827,21 @@ package android.app.wallpapereffectsgeneration {
|
||||
|
||||
}
|
||||
|
||||
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>);
|
||||
field public static final int STATUS_ACCESS_DENIED = 5; // 0x5
|
||||
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
|
||||
field public static final int STATUS_UNSUPPORTED = 2; // 0x2
|
||||
field public static final int STATUS_WEARABLE_UNAVAILABLE = 4; // 0x4
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
package android.apphibernation {
|
||||
|
||||
public class AppHibernationManager {
|
||||
@@ -3074,6 +3091,7 @@ package android.content {
|
||||
field public static final String UWB_SERVICE = "uwb";
|
||||
field public static final String VR_SERVICE = "vrmanager";
|
||||
field public static final String WALLPAPER_EFFECTS_GENERATION_SERVICE = "wallpaper_effects_generation";
|
||||
field public static final String WEARABLE_SENSING_SERVICE = "wearable_sensing";
|
||||
field public static final String WIFI_NL80211_SERVICE = "wifinl80211";
|
||||
field @Deprecated public static final String WIFI_RTT_SERVICE = "rttmanager";
|
||||
field public static final String WIFI_SCANNING_SERVICE = "wifiscanner";
|
||||
@@ -10513,6 +10531,7 @@ package android.provider {
|
||||
field public static final String NAMESPACE_TEXTCLASSIFIER = "textclassifier";
|
||||
field public static final String NAMESPACE_TRANSPARENCY_METADATA = "transparency_metadata";
|
||||
field public static final String NAMESPACE_UWB = "uwb";
|
||||
field public static final String NAMESPACE_WEARABLE_SENSING = "wearable_sensing";
|
||||
field public static final String NAMESPACE_WINDOW_MANAGER_NATIVE_BOOT = "window_manager_native_boot";
|
||||
}
|
||||
|
||||
@@ -12263,6 +12282,18 @@ package android.service.watchdog {
|
||||
|
||||
}
|
||||
|
||||
package android.service.wearable {
|
||||
|
||||
public abstract class WearableSensingService extends android.app.Service {
|
||||
ctor public WearableSensingService();
|
||||
method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
|
||||
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>);
|
||||
field public static final String SERVICE_INTERFACE = "android.service.wearable.WearableSensingService";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
package android.telecom {
|
||||
|
||||
@Deprecated public class AudioState implements android.os.Parcelable {
|
||||
|
||||
34
core/java/android/app/wearable/IWearableSensingManager.aidl
Normal file
34
core/java/android/app/wearable/IWearableSensingManager.aidl
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.app.wearable;
|
||||
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.PersistableBundle;
|
||||
import android.os.RemoteCallback;
|
||||
import android.os.SharedMemory;
|
||||
|
||||
/**
|
||||
* Interface for a WearableSensingManager for managing wearable sensing service.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
interface IWearableSensingManager {
|
||||
@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)")
|
||||
void provideData(in PersistableBundle data, in SharedMemory sharedMemory, in RemoteCallback callback);
|
||||
}
|
||||
3
core/java/android/app/wearable/OWNERS
Normal file
3
core/java/android/app/wearable/OWNERS
Normal file
@@ -0,0 +1,3 @@
|
||||
charliewang@google.com
|
||||
oni@google.com
|
||||
volnov@google.com
|
||||
193
core/java/android/app/wearable/WearableSensingManager.java
Normal file
193
core/java/android/app/wearable/WearableSensingManager.java
Normal file
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* 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.app.wearable;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.CallbackExecutor;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.annotation.SystemApi;
|
||||
import android.annotation.SystemService;
|
||||
import android.app.ambientcontext.AmbientContextEvent;
|
||||
import android.content.Context;
|
||||
import android.os.Binder;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.PersistableBundle;
|
||||
import android.os.RemoteCallback;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SharedMemory;
|
||||
import android.service.wearable.WearableSensingService;
|
||||
import android.system.OsConstants;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Allows granted apps to manage the WearableSensingService.
|
||||
* Applications are responsible for managing the connection to Wearables. Applications can choose
|
||||
* to provide a data stream to the WearableSensingService to use for
|
||||
* computing {@link AmbientContextEvent}s. Applications can also optionally provide their own
|
||||
* defined data to power the detection of {@link AmbientContextEvent}s.
|
||||
* Methods on this class requires the caller to hold and be granted the
|
||||
* {@link Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
|
||||
@SystemApi
|
||||
@SystemService(Context.WEARABLE_SENSING_SERVICE)
|
||||
public class WearableSensingManager {
|
||||
/**
|
||||
* The bundle key for the service status query result, used in
|
||||
* {@code RemoteCallback#sendResult}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static final String STATUS_RESPONSE_BUNDLE_KEY =
|
||||
"android.app.wearable.WearableSensingStatusBundleKey";
|
||||
|
||||
|
||||
/**
|
||||
* An unknown status.
|
||||
*/
|
||||
public static final int STATUS_UNKNOWN = 0;
|
||||
|
||||
/**
|
||||
* The value of the status code that indicates success.
|
||||
*/
|
||||
public static final int STATUS_SUCCESS = 1;
|
||||
|
||||
/**
|
||||
* The value of the status code that indicates one or more of the
|
||||
* requested events are not supported.
|
||||
*/
|
||||
public static final int STATUS_UNSUPPORTED = 2;
|
||||
|
||||
/**
|
||||
* The value of the status code that indicates service not available.
|
||||
*/
|
||||
public static final int STATUS_SERVICE_UNAVAILABLE = 3;
|
||||
|
||||
/**
|
||||
* The value of the status code that there's no connection to the wearable.
|
||||
*/
|
||||
public static final int STATUS_WEARABLE_UNAVAILABLE = 4;
|
||||
|
||||
/**
|
||||
* The value of the status code that the app is not granted access.
|
||||
*/
|
||||
public static final int STATUS_ACCESS_DENIED = 5;
|
||||
|
||||
/** @hide */
|
||||
@IntDef(prefix = { "STATUS_" }, value = {
|
||||
STATUS_UNKNOWN,
|
||||
STATUS_SUCCESS,
|
||||
STATUS_UNSUPPORTED,
|
||||
STATUS_SERVICE_UNAVAILABLE,
|
||||
STATUS_WEARABLE_UNAVAILABLE,
|
||||
STATUS_ACCESS_DENIED
|
||||
}) public @interface StatusCode {}
|
||||
|
||||
private final Context mContext;
|
||||
private final IWearableSensingManager mService;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
public WearableSensingManager(Context context, IWearableSensingManager service) {
|
||||
mContext = context;
|
||||
mService = service;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* This is used by applications that will also provide an implementation of
|
||||
* an isolated WearableSensingService. If the data stream was provided successfully
|
||||
* {@link WearableSensingManager#STATUS_SUCCESS} will be provided.
|
||||
*
|
||||
* @param parcelFileDescriptor The data stream to provide
|
||||
* @param executor Executor on which to run the consumer callback
|
||||
* @param statusConsumer A consumer that handles the status codes, which is returned
|
||||
* right after the call.
|
||||
*/
|
||||
@RequiresPermission(Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE)
|
||||
public void provideDataStream(
|
||||
@NonNull ParcelFileDescriptor parcelFileDescriptor,
|
||||
@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);
|
||||
}
|
||||
});
|
||||
mService.provideDataStream(parcelFileDescriptor, callback);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets configuration and provides read-only data in a {@link PersistableBundle} that may be
|
||||
* used by the WearableSensingService, and sends the result to the {@link Consumer}
|
||||
* right after the call. It is dependent on the application to
|
||||
* define the type of data to provide. This is used by applications that will also
|
||||
* provide an implementation of an isolated WearableSensingService. If the data was
|
||||
* provided successfully {@link WearableSensingManager#STATUS_SUCCESS} will be povided.
|
||||
*
|
||||
* @param data Application configuration data to provide to the {@link WearableSensingService}.
|
||||
* PersistableBundle does not allow any remotable objects or other contents
|
||||
* that can be used to communicate with other processes.
|
||||
* @param sharedMemory The unrestricted data blob to
|
||||
* provide to the {@link WearableSensingService}. Use this to provide the
|
||||
* sensing models data or other such data to the trusted process.
|
||||
* The sharedMemory must be read only and protected with
|
||||
* {@link OsConstants.PROT_READ}.
|
||||
* Other operations will be removed by the system.
|
||||
* @param executor Executor on which to run the consumer callback
|
||||
* @param statusConsumer A consumer that handles the status codes, which is returned
|
||||
* right after the call
|
||||
*/
|
||||
@RequiresPermission(Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE)
|
||||
public void provideData(
|
||||
@NonNull PersistableBundle data, @Nullable SharedMemory sharedMemory,
|
||||
@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);
|
||||
}
|
||||
});
|
||||
mService.provideData(data, sharedMemory, callback);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6072,6 +6072,17 @@ public abstract class Context {
|
||||
@SystemApi
|
||||
public static final String AMBIENT_CONTEXT_SERVICE = "ambient_context";
|
||||
|
||||
/**
|
||||
* Use with {@link #getSystemService(String)} to retrieve a
|
||||
* {@link android.app.wearable.WearableSensingManager}.
|
||||
*
|
||||
* @see #getSystemService(String)
|
||||
* @see WearableSensingManager
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public static final String WEARABLE_SENSING_SERVICE = "wearable_sensing";
|
||||
|
||||
/**
|
||||
* Use with {@link #getSystemService(String)} to retrieve a
|
||||
* {@link android.healthconnect.HealthConnectManager}.
|
||||
|
||||
@@ -764,6 +764,15 @@ public final class DeviceConfig {
|
||||
public static final String NAMESPACE_AMBIENT_CONTEXT_MANAGER_SERVICE =
|
||||
"ambient_context_manager_service";
|
||||
|
||||
/**
|
||||
* Namespace for WearableSensingManagerService related features.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public static final String NAMESPACE_WEARABLE_SENSING =
|
||||
"wearable_sensing";
|
||||
|
||||
/**
|
||||
* Namespace for Vendor System Native related features.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.service.wearable;
|
||||
|
||||
import android.os.PersistableBundle;
|
||||
import android.os.RemoteCallback;
|
||||
import android.os.SharedMemory;
|
||||
|
||||
/**
|
||||
* Interface for a concrete implementation to provide AmbientContextEvents to the framework for
|
||||
* wearables.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
oneway interface IWearableSensingService {
|
||||
void provideDataStream(in ParcelFileDescriptor parcelFileDescriptor, in RemoteCallback callback);
|
||||
void provideData(in PersistableBundle data, in SharedMemory sharedMemory, in RemoteCallback callback);
|
||||
}
|
||||
3
core/java/android/service/wearable/OWNERS
Normal file
3
core/java/android/service/wearable/OWNERS
Normal file
@@ -0,0 +1,3 @@
|
||||
charliewang@google.com
|
||||
oni@google.com
|
||||
volnov@google.com
|
||||
158
core/java/android/service/wearable/WearableSensingService.java
Normal file
158
core/java/android/service/wearable/WearableSensingService.java
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* 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.service.wearable;
|
||||
|
||||
import android.annotation.BinderThread;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.app.Service;
|
||||
import android.app.ambientcontext.AmbientContextEvent;
|
||||
import android.app.wearable.WearableSensingManager;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.PersistableBundle;
|
||||
import android.os.RemoteCallback;
|
||||
import android.os.SharedMemory;
|
||||
import android.util.Slog;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Abstract base class for sensing with wearable devices. An example of this is {@link
|
||||
*AmbientContextEvent} detection.
|
||||
*
|
||||
* <p> A service that provides requested sensing events to the system, such as a {@link
|
||||
*AmbientContextEvent}. The system's default WearableSensingService implementation is configured in
|
||||
* {@code config_defaultWearableSensingService}. If this config has no value, a stub is
|
||||
* returned.
|
||||
*
|
||||
* <p> An implementation of a WearableSensingService should be an isolated service. Using the
|
||||
* "isolatedProcess=true" attribute in the service's configurations. </p>
|
||||
**
|
||||
* <pre>
|
||||
* {@literal
|
||||
* <service android:name=".YourWearableSensingService"
|
||||
* android:permission="android.permission.BIND_WEARABLE_SENSING_SERVICE"
|
||||
* android:isolatedProcess="true">
|
||||
* </service>}
|
||||
* </pre>
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public abstract class WearableSensingService extends Service {
|
||||
private static final String TAG = WearableSensingService.class.getSimpleName();
|
||||
|
||||
/**
|
||||
* The bundle key for this class of object, used in {@code RemoteCallback#sendResult}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static final String STATUS_RESPONSE_BUNDLE_KEY =
|
||||
"android.app.wearable.WearableSensingStatusBundleKey";
|
||||
|
||||
/**
|
||||
* The {@link Intent} that must be declared as handled by the service. To be supported, the
|
||||
* service must also require the
|
||||
* {@link android.Manifest.permission#BIND_WEARABLE_SENSING_SERVICE}
|
||||
* permission so that other applications can not abuse it.
|
||||
*/
|
||||
public static final String SERVICE_INTERFACE =
|
||||
"android.service.wearable.WearableSensingService";
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public final IBinder onBind(@NonNull Intent intent) {
|
||||
if (SERVICE_INTERFACE.equals(intent.getAction())) {
|
||||
return new IWearableSensingService.Stub() {
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void provideDataStream(
|
||||
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);
|
||||
};
|
||||
WearableSensingService.this.onDataStreamProvided(
|
||||
parcelFileDescriptor, consumer);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void provideData(
|
||||
PersistableBundle data,
|
||||
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);
|
||||
};
|
||||
WearableSensingService.this.onDataProvided(data, sharedMemory, consumer);
|
||||
}
|
||||
};
|
||||
}
|
||||
Slog.w(TAG, "Incorrect service interface, returning null.");
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* close the data stream when it is finished.
|
||||
*
|
||||
* @param parcelFileDescriptor The data stream to the wearable
|
||||
* @param statusConsumer the consumer for the service status.
|
||||
*/
|
||||
@BinderThread
|
||||
public abstract void onDataStreamProvided(@NonNull ParcelFileDescriptor parcelFileDescriptor,
|
||||
@NonNull Consumer<Integer> statusConsumer);
|
||||
|
||||
/**
|
||||
* Called when configurations and read-only data in a {@link PersistableBundle}
|
||||
* can be used by the WearableSensingService and sends the result to the {@link Consumer}
|
||||
* right after the call. It is dependent on the application to define the type of data to
|
||||
* provide. This is used by applications that will also provide an implementation of an isolated
|
||||
* WearableSensingService. If the data was provided successfully
|
||||
* {@link WearableSensingManager#STATUS_SUCCESS} will be provided.
|
||||
*
|
||||
* @param data Application configuration data to provide to the {@link WearableSensingService}.
|
||||
* PersistableBundle does not allow any remotable objects or other contents
|
||||
* that can be used to communicate with other processes.
|
||||
* @param sharedMemory The unrestricted data blob to
|
||||
* provide to the {@link WearableSensingService}. Use this to provide the
|
||||
* sensing models data or other such data to the trusted process.
|
||||
* @param statusConsumer the consumer for the service status.
|
||||
*/
|
||||
@BinderThread
|
||||
public abstract void onDataProvided(
|
||||
@NonNull PersistableBundle data,
|
||||
@Nullable SharedMemory sharedMemory,
|
||||
@NonNull Consumer<Integer> statusConsumer);
|
||||
}
|
||||
@@ -6641,6 +6641,21 @@
|
||||
<permission android:name="android.permission.MANAGE_DEVICE_LOCK_STATE"
|
||||
android:protectionLevel="internal|role" />
|
||||
|
||||
<!-- @SystemApi Required by a WearableSensingService to
|
||||
ensure that only the caller with this permission can bind to it.
|
||||
<p> Protection level: signature
|
||||
@hide
|
||||
-->
|
||||
<permission android:name="android.permission.BIND_WEARABLE_SENSING_SERVICE"
|
||||
android:protectionLevel="signature" />
|
||||
|
||||
<!-- @SystemApi Allows an app to manage the wearable sensing service.
|
||||
<p>Protection level: signature|privileged
|
||||
@hide
|
||||
-->
|
||||
<permission android:name="android.permission.MANAGE_WEARABLE_SENSING_SERVICE"
|
||||
android:protectionLevel="signature|privileged" />
|
||||
|
||||
<!-- Allows applications to use the long running jobs APIs.
|
||||
<p>This is a special access permission that can be revoked by the system or the user.
|
||||
<p>Apps need to target API {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or above
|
||||
|
||||
@@ -4135,6 +4135,12 @@
|
||||
-->
|
||||
<string name="config_defaultAmbientContextDetectionService" translatable="false"></string>
|
||||
|
||||
<!-- The component name for the default system wearable sensing service.
|
||||
This service must be trusted, as it can be activated without explicit consent of the user.
|
||||
See android.service.wearable.WearableSensingService.
|
||||
-->
|
||||
<string name="config_defaultWearableSensingService" translatable="false"></string>
|
||||
|
||||
<!-- Component name that accepts ACTION_SEND intents for requesting ambient context consent. -->
|
||||
<string translatable="false" name="config_defaultAmbientContextConsentComponent"></string>
|
||||
|
||||
|
||||
@@ -3768,6 +3768,7 @@
|
||||
<java-symbol type="string" name="config_defaultAmbientContextConsentComponent" />
|
||||
<java-symbol type="string" name="config_ambientContextPackageNameExtraKey" />
|
||||
<java-symbol type="string" name="config_ambientContextEventArrayExtraKey" />
|
||||
<java-symbol type="string" name="config_defaultWearableSensingService" />
|
||||
<java-symbol type="string" name="config_retailDemoPackage" />
|
||||
<java-symbol type="string" name="config_retailDemoPackageSignature" />
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ public final class KnownPackages {
|
||||
PACKAGE_RETAIL_DEMO,
|
||||
PACKAGE_RECENTS,
|
||||
PACKAGE_AMBIENT_CONTEXT_DETECTION,
|
||||
PACKAGE_WEARABLE_SENSING,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface KnownPackage {
|
||||
@@ -71,9 +72,10 @@ public final class KnownPackages {
|
||||
public static final int PACKAGE_RETAIL_DEMO = 16;
|
||||
public static final int PACKAGE_RECENTS = 17;
|
||||
public static final int PACKAGE_AMBIENT_CONTEXT_DETECTION = 18;
|
||||
public static final int PACKAGE_WEARABLE_SENSING = 19;
|
||||
// Integer value of the last known package ID. Increases as new ID is added to KnownPackage.
|
||||
// Please note the numbers should be continuous.
|
||||
public static final int LAST_KNOWN_PACKAGE = PACKAGE_AMBIENT_CONTEXT_DETECTION;
|
||||
public static final int LAST_KNOWN_PACKAGE = PACKAGE_WEARABLE_SENSING;
|
||||
|
||||
private final DefaultAppProvider mDefaultAppProvider;
|
||||
private final String mRequiredInstallerPackage;
|
||||
@@ -86,6 +88,7 @@ public final class KnownPackages {
|
||||
private final String mConfiguratorPackage;
|
||||
private final String mIncidentReportApproverPackage;
|
||||
private final String mAmbientContextDetectionPackage;
|
||||
private final String mWearableSensingPackage;
|
||||
private final String mAppPredictionServicePackage;
|
||||
private final String mCompanionPackage;
|
||||
private final String mRetailDemoPackage;
|
||||
@@ -97,9 +100,9 @@ public final class KnownPackages {
|
||||
String[] requiredVerifierPackages, String defaultTextClassifierPackage,
|
||||
String systemTextClassifierPackageName, String requiredPermissionControllerPackage,
|
||||
String configuratorPackage, String incidentReportApproverPackage,
|
||||
String ambientContextDetectionPackage, String appPredictionServicePackage,
|
||||
String companionPackageName, String retailDemoPackage,
|
||||
String overlayConfigSignaturePackage, String recentsPackage) {
|
||||
String ambientContextDetectionPackage, String wearableSensingPackage,
|
||||
String appPredictionServicePackage, String companionPackageName,
|
||||
String retailDemoPackage, String overlayConfigSignaturePackage, String recentsPackage) {
|
||||
mDefaultAppProvider = defaultAppProvider;
|
||||
mRequiredInstallerPackage = requiredInstallerPackage;
|
||||
mRequiredUninstallerPackage = requiredUninstallerPackage;
|
||||
@@ -111,6 +114,7 @@ public final class KnownPackages {
|
||||
mConfiguratorPackage = configuratorPackage;
|
||||
mIncidentReportApproverPackage = incidentReportApproverPackage;
|
||||
mAmbientContextDetectionPackage = ambientContextDetectionPackage;
|
||||
mWearableSensingPackage = wearableSensingPackage;
|
||||
mAppPredictionServicePackage = appPredictionServicePackage;
|
||||
mCompanionPackage = companionPackageName;
|
||||
mRetailDemoPackage = retailDemoPackage;
|
||||
@@ -165,6 +169,8 @@ public final class KnownPackages {
|
||||
return "Recents";
|
||||
case PACKAGE_AMBIENT_CONTEXT_DETECTION:
|
||||
return "Ambient Context Detection";
|
||||
case PACKAGE_WEARABLE_SENSING:
|
||||
return "Wearable sensing";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
@@ -194,6 +200,8 @@ public final class KnownPackages {
|
||||
return snapshot.filterOnlySystemPackages(mIncidentReportApproverPackage);
|
||||
case PACKAGE_AMBIENT_CONTEXT_DETECTION:
|
||||
return snapshot.filterOnlySystemPackages(mAmbientContextDetectionPackage);
|
||||
case PACKAGE_WEARABLE_SENSING:
|
||||
return snapshot.filterOnlySystemPackages(mWearableSensingPackage);
|
||||
case PACKAGE_APP_PREDICTOR:
|
||||
return snapshot.filterOnlySystemPackages(mAppPredictionServicePackage);
|
||||
case PACKAGE_COMPANION:
|
||||
|
||||
@@ -937,6 +937,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
|
||||
final @Nullable String mOverlayConfigSignaturePackage;
|
||||
final @Nullable String mRecentsPackage;
|
||||
final @Nullable String mAmbientContextDetectionPackage;
|
||||
final @Nullable String mWearableSensingPackage;
|
||||
private final @NonNull String mRequiredSdkSandboxPackage;
|
||||
|
||||
@GuardedBy("mLock")
|
||||
@@ -1682,6 +1683,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
|
||||
mRetailDemoPackage = testParams.retailDemoPackage;
|
||||
mRecentsPackage = testParams.recentsPackage;
|
||||
mAmbientContextDetectionPackage = testParams.ambientContextDetectionPackage;
|
||||
mWearableSensingPackage = testParams.wearableSensingPackage;
|
||||
mConfiguratorPackage = testParams.configuratorPackage;
|
||||
mAppPredictionServicePackage = testParams.appPredictionServicePackage;
|
||||
mIncidentReportApproverPackage = testParams.incidentReportApproverPackage;
|
||||
@@ -2039,6 +2041,9 @@ public class PackageManagerService implements PackageSender, TestUtilityService
|
||||
mAmbientContextDetectionPackage = ensureSystemPackageName(computer,
|
||||
getPackageFromComponentString(
|
||||
R.string.config_defaultAmbientContextDetectionService));
|
||||
mWearableSensingPackage = ensureSystemPackageName(computer,
|
||||
getPackageFromComponentString(
|
||||
R.string.config_defaultWearableSensingService));
|
||||
|
||||
// Now that we know all of the shared libraries, update all clients to have
|
||||
// the correct library paths.
|
||||
@@ -6031,6 +6036,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
|
||||
mConfiguratorPackage,
|
||||
mIncidentReportApproverPackage,
|
||||
mAmbientContextDetectionPackage,
|
||||
mWearableSensingPackage,
|
||||
mAppPredictionServicePackage,
|
||||
COMPANION_PACKAGE_NAME,
|
||||
mRetailDemoPackage,
|
||||
@@ -7064,6 +7070,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
|
||||
mConfiguratorPackage,
|
||||
mIncidentReportApproverPackage,
|
||||
mAmbientContextDetectionPackage,
|
||||
mWearableSensingPackage,
|
||||
mAppPredictionServicePackage,
|
||||
COMPANION_PACKAGE_NAME,
|
||||
mRetailDemoPackage,
|
||||
|
||||
@@ -94,6 +94,7 @@ public final class PackageManagerServiceTestParams {
|
||||
public @Nullable String retailDemoPackage;
|
||||
public @Nullable String recentsPackage;
|
||||
public @Nullable String ambientContextDetectionPackage;
|
||||
public @Nullable String wearableSensingPackage;
|
||||
public ComponentName resolveComponentName;
|
||||
public ArrayMap<String, AndroidPackage> packages;
|
||||
public boolean enableFreeCacheV2;
|
||||
|
||||
3
services/core/java/com/android/server/wearable/OWNERS
Normal file
3
services/core/java/com/android/server/wearable/OWNERS
Normal file
@@ -0,0 +1,3 @@
|
||||
charliewang@google.com
|
||||
oni@google.com
|
||||
volnov@google.com
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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.wearable;
|
||||
|
||||
import static android.content.Context.BIND_FOREGROUND_SERVICE;
|
||||
import static android.content.Context.BIND_INCLUDE_CAPABILITIES;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.PersistableBundle;
|
||||
import android.os.RemoteCallback;
|
||||
import android.os.SharedMemory;
|
||||
import android.service.wearable.IWearableSensingService;
|
||||
import android.service.wearable.WearableSensingService;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.infra.ServiceConnector;
|
||||
|
||||
/** Manages the connection to the remote wearable sensing service. */
|
||||
final class RemoteWearableSensingService extends ServiceConnector.Impl<IWearableSensingService> {
|
||||
private static final String TAG =
|
||||
com.android.server.wearable.RemoteWearableSensingService.class.getSimpleName();
|
||||
private final static boolean DEBUG = false;
|
||||
|
||||
RemoteWearableSensingService(Context context, ComponentName serviceName,
|
||||
int userId) {
|
||||
super(context, new Intent(
|
||||
WearableSensingService.SERVICE_INTERFACE).setComponent(serviceName),
|
||||
BIND_FOREGROUND_SERVICE | BIND_INCLUDE_CAPABILITIES, userId,
|
||||
IWearableSensingService.Stub::asInterface);
|
||||
|
||||
// Bind right away
|
||||
connect();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getAutoDisconnectTimeoutMs() {
|
||||
// Disable automatic unbinding.
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the implementation a data stream to the wearable.
|
||||
*
|
||||
* @param parcelFileDescriptor The data stream to the wearable
|
||||
* @param callback The callback for service status
|
||||
*/
|
||||
public void provideDataStream(ParcelFileDescriptor parcelFileDescriptor,
|
||||
RemoteCallback callback) {
|
||||
if (DEBUG) {
|
||||
Slog.i(TAG, "Providing data stream.");
|
||||
}
|
||||
post(service -> service.provideDataStream(parcelFileDescriptor, callback));
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the implementation data.
|
||||
*
|
||||
* @param data Application configuration data to provide to the implementation.
|
||||
* @param sharedMemory The unrestricted data blob to provide to the implementation.
|
||||
* @param callback The callback for service status
|
||||
*/
|
||||
public void provideData(PersistableBundle data,
|
||||
SharedMemory sharedMemory,
|
||||
RemoteCallback callback) {
|
||||
if (DEBUG) {
|
||||
Slog.i(TAG, "Providing data.");
|
||||
}
|
||||
post(service -> service.provideData(data, sharedMemory, callback));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* 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.wearable;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.AppGlobals;
|
||||
import android.app.ambientcontext.AmbientContextEvent;
|
||||
import android.app.wearable.WearableSensingManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.os.Bundle;
|
||||
import android.system.OsConstants;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.PersistableBundle;
|
||||
import android.os.RemoteCallback;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SharedMemory;
|
||||
import android.util.IndentingPrintWriter;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.server.infra.AbstractPerUserSystemService;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* Per-user manager service for managing sensing {@link AmbientContextEvent}s on Wearables.
|
||||
*/
|
||||
final class WearableSensingManagerPerUserService extends
|
||||
AbstractPerUserSystemService<WearableSensingManagerPerUserService,
|
||||
WearableSensingManagerService> {
|
||||
private static final String TAG = WearableSensingManagerPerUserService.class.getSimpleName();
|
||||
|
||||
@Nullable
|
||||
@VisibleForTesting
|
||||
RemoteWearableSensingService mRemoteService;
|
||||
|
||||
private ComponentName mComponentName;
|
||||
|
||||
WearableSensingManagerPerUserService(
|
||||
@NonNull WearableSensingManagerService master, Object lock, @UserIdInt int userId) {
|
||||
super(master, lock, userId);
|
||||
}
|
||||
|
||||
static void notifyStatusCallback(RemoteCallback statusCallback, int statusCode) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putInt(
|
||||
WearableSensingManager.STATUS_RESPONSE_BUNDLE_KEY, statusCode);
|
||||
statusCallback.sendResult(bundle);
|
||||
}
|
||||
|
||||
void destroyLocked() {
|
||||
Slog.d(TAG, "Trying to cancel the remote request. Reason: Service destroyed.");
|
||||
if (mRemoteService != null) {
|
||||
synchronized (mLock) {
|
||||
mRemoteService.unbind();
|
||||
mRemoteService = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void ensureRemoteServiceInitiated() {
|
||||
if (mRemoteService == null) {
|
||||
mRemoteService = new RemoteWearableSensingService(
|
||||
getContext(), mComponentName, getUserId());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get the currently bound component name.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
ComponentName getComponentName() {
|
||||
return mComponentName;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resolves and sets up the service if it had not been done yet. Returns true if the service
|
||||
* is available.
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
@VisibleForTesting
|
||||
boolean setUpServiceIfNeeded() {
|
||||
if (mComponentName == null) {
|
||||
mComponentName = updateServiceInfoLocked();
|
||||
}
|
||||
if (mComponentName == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ServiceInfo serviceInfo;
|
||||
try {
|
||||
serviceInfo = AppGlobals.getPackageManager().getServiceInfo(
|
||||
mComponentName, 0, mUserId);
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "RemoteException while setting up service");
|
||||
return false;
|
||||
}
|
||||
return serviceInfo != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ServiceInfo newServiceInfoLocked(@NonNull ComponentName serviceComponent)
|
||||
throws PackageManager.NameNotFoundException {
|
||||
ServiceInfo serviceInfo;
|
||||
try {
|
||||
serviceInfo = AppGlobals.getPackageManager().getServiceInfo(serviceComponent,
|
||||
0, mUserId);
|
||||
if (serviceInfo != null) {
|
||||
final String permission = serviceInfo.permission;
|
||||
if (!Manifest.permission.BIND_WEARABLE_SENSING_SERVICE.equals(
|
||||
permission)) {
|
||||
throw new SecurityException(String.format(
|
||||
"Service %s requires %s permission. Found %s permission",
|
||||
serviceInfo.getComponentName(),
|
||||
Manifest.permission.BIND_WEARABLE_SENSING_SERVICE,
|
||||
serviceInfo.permission));
|
||||
}
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
throw new PackageManager.NameNotFoundException(
|
||||
"Could not get service for " + serviceComponent);
|
||||
}
|
||||
return serviceInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dumpLocked(@NonNull String prefix, @NonNull PrintWriter pw) {
|
||||
synchronized (super.mLock) {
|
||||
super.dumpLocked(prefix, pw);
|
||||
}
|
||||
if (mRemoteService != null) {
|
||||
mRemoteService.dump("", new IndentingPrintWriter(pw, " "));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles sending the provided data stream for the wearable to the wearable sensing service.
|
||||
*/
|
||||
public void onProvideDataStream(
|
||||
ParcelFileDescriptor parcelFileDescriptor,
|
||||
RemoteCallback callback) {
|
||||
Slog.i(TAG, "onProvideDataStream in per user service.");
|
||||
synchronized (mLock) {
|
||||
if (!setUpServiceIfNeeded()) {
|
||||
Slog.w(TAG, "Detection service is not available at this moment.");
|
||||
notifyStatusCallback(callback, WearableSensingManager.STATUS_SERVICE_UNAVAILABLE);
|
||||
return;
|
||||
}
|
||||
Slog.i(TAG, "calling over to remote servvice.");
|
||||
ensureRemoteServiceInitiated();
|
||||
mRemoteService.provideDataStream(parcelFileDescriptor, callback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles sending the provided data to the wearable sensing service.
|
||||
*/
|
||||
public void onProvidedData(PersistableBundle data,
|
||||
SharedMemory sharedMemory,
|
||||
RemoteCallback callback) {
|
||||
synchronized (mLock) {
|
||||
if (!setUpServiceIfNeeded()) {
|
||||
Slog.w(TAG, "Detection service is not available at this moment.");
|
||||
notifyStatusCallback(callback, WearableSensingManager.STATUS_SERVICE_UNAVAILABLE);
|
||||
return;
|
||||
}
|
||||
ensureRemoteServiceInitiated();
|
||||
if (sharedMemory != null) {
|
||||
sharedMemory.setProtect(OsConstants.PROT_READ);
|
||||
}
|
||||
mRemoteService.provideData(data, sharedMemory, callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* 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.wearable;
|
||||
|
||||
import static android.provider.DeviceConfig.NAMESPACE_WEARABLE_SENSING;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.ambientcontext.AmbientContextEvent;
|
||||
import android.app.wearable.IWearableSensingManager;
|
||||
import android.app.wearable.WearableSensingManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManagerInternal;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.PersistableBundle;
|
||||
import android.os.RemoteCallback;
|
||||
import android.os.ResultReceiver;
|
||||
import android.os.SharedMemory;
|
||||
import android.os.ShellCallback;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.DeviceConfig;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.SystemService;
|
||||
import com.android.server.infra.AbstractMasterSystemService;
|
||||
import com.android.server.infra.FrameworkResourcesServiceNameResolver;
|
||||
import com.android.server.pm.KnownPackages;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* System service for managing sensing {@link AmbientContextEvent}s on Wearables.
|
||||
*/
|
||||
public class WearableSensingManagerService extends
|
||||
AbstractMasterSystemService<WearableSensingManagerService,
|
||||
WearableSensingManagerPerUserService> {
|
||||
private static final String TAG = WearableSensingManagerService.class.getSimpleName();
|
||||
private static final String KEY_SERVICE_ENABLED = "service_enabled";
|
||||
|
||||
/** Default value in absence of {@link DeviceConfig} override. */
|
||||
private static final boolean DEFAULT_SERVICE_ENABLED = true;
|
||||
public static final int MAX_TEMPORARY_SERVICE_DURATION_MS = 30000;
|
||||
|
||||
private final Context mContext;
|
||||
volatile boolean mIsServiceEnabled;
|
||||
|
||||
public WearableSensingManagerService(Context context) {
|
||||
super(context,
|
||||
new FrameworkResourcesServiceNameResolver(
|
||||
context,
|
||||
R.string.config_defaultWearableSensingService),
|
||||
/*disallowProperty=*/null,
|
||||
PACKAGE_UPDATE_POLICY_REFRESH_EAGER
|
||||
| /*To avoid high latency*/ PACKAGE_RESTART_POLICY_REFRESH_EAGER);
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
publishBinderService(
|
||||
Context.WEARABLE_SENSING_SERVICE, new WearableSensingManagerInternal());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBootPhase(int phase) {
|
||||
if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
|
||||
DeviceConfig.addOnPropertiesChangedListener(
|
||||
NAMESPACE_WEARABLE_SENSING,
|
||||
getContext().getMainExecutor(),
|
||||
(properties) -> onDeviceConfigChange(properties.getKeyset()));
|
||||
|
||||
mIsServiceEnabled = DeviceConfig.getBoolean(
|
||||
NAMESPACE_WEARABLE_SENSING,
|
||||
KEY_SERVICE_ENABLED, DEFAULT_SERVICE_ENABLED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void onDeviceConfigChange(@NonNull Set<String> keys) {
|
||||
if (keys.contains(KEY_SERVICE_ENABLED)) {
|
||||
mIsServiceEnabled = DeviceConfig.getBoolean(
|
||||
NAMESPACE_WEARABLE_SENSING,
|
||||
KEY_SERVICE_ENABLED, DEFAULT_SERVICE_ENABLED);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected WearableSensingManagerPerUserService newServiceLocked(int resolvedUserId,
|
||||
boolean disabled) {
|
||||
return new WearableSensingManagerPerUserService(this, mLock, resolvedUserId);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onServiceRemoved(
|
||||
WearableSensingManagerPerUserService service, @UserIdInt int userId) {
|
||||
Slog.d(TAG, "onServiceRemoved");
|
||||
service.destroyLocked();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onServicePackageRestartedLocked(@UserIdInt int userId) {
|
||||
Slog.d(TAG, "onServicePackageRestartedLocked.");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onServicePackageUpdatedLocked(@UserIdInt int userId) {
|
||||
Slog.d(TAG, "onServicePackageUpdatedLocked.");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void enforceCallingPermissionForManagement() {
|
||||
getContext().enforceCallingPermission(
|
||||
Manifest.permission.ACCESS_AMBIENT_CONTEXT_EVENT, TAG);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getMaximumTemporaryServiceDurationMs() {
|
||||
return MAX_TEMPORARY_SERVICE_DURATION_MS;
|
||||
}
|
||||
|
||||
/** Returns {@code true} if the detection service is configured on this device. */
|
||||
public static boolean isDetectionServiceConfigured() {
|
||||
final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
|
||||
final String[] packageNames = pmi.getKnownPackageNames(
|
||||
KnownPackages.PACKAGE_WEARABLE_SENSING, UserHandle.USER_SYSTEM);
|
||||
boolean isServiceConfigured = (packageNames.length != 0);
|
||||
Slog.i(TAG, "Wearable sensing service configured: " + isServiceConfigured);
|
||||
return isServiceConfigured;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the AmbientContextManagerPerUserService component for this user.
|
||||
*/
|
||||
public ComponentName getComponentName(@UserIdInt int userId) {
|
||||
synchronized (mLock) {
|
||||
final WearableSensingManagerPerUserService service = getServiceForUserLocked(userId);
|
||||
if (service != null) {
|
||||
return service.getComponentName();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private final class WearableSensingManagerInternal extends IWearableSensingManager.Stub {
|
||||
final WearableSensingManagerPerUserService mService = getServiceForUserLocked(
|
||||
UserHandle.getCallingUserId());
|
||||
|
||||
@Override
|
||||
public void provideDataStream(
|
||||
ParcelFileDescriptor parcelFileDescriptor,
|
||||
RemoteCallback callback) {
|
||||
Slog.i(TAG, "WearableSensingManagerInternal provideDataStream.");
|
||||
Objects.requireNonNull(parcelFileDescriptor);
|
||||
Objects.requireNonNull(callback);
|
||||
mContext.enforceCallingOrSelfPermission(
|
||||
Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE, TAG);
|
||||
if (!mIsServiceEnabled) {
|
||||
Slog.w(TAG, "Service not available.");
|
||||
WearableSensingManagerPerUserService.notifyStatusCallback(callback,
|
||||
WearableSensingManager.STATUS_SERVICE_UNAVAILABLE);
|
||||
return;
|
||||
}
|
||||
mService.onProvideDataStream(parcelFileDescriptor, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void provideData(
|
||||
PersistableBundle data,
|
||||
SharedMemory sharedMemory,
|
||||
RemoteCallback callback) {
|
||||
Slog.i(TAG, "WearableSensingManagerInternal provideData.");
|
||||
Objects.requireNonNull(data);
|
||||
Objects.requireNonNull(callback);
|
||||
mContext.enforceCallingOrSelfPermission(
|
||||
Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE, TAG);
|
||||
if (!mIsServiceEnabled) {
|
||||
Slog.w(TAG, "Service not available.");
|
||||
WearableSensingManagerPerUserService.notifyStatusCallback(callback,
|
||||
WearableSensingManager.STATUS_SERVICE_UNAVAILABLE);
|
||||
return;
|
||||
}
|
||||
mService.onProvidedData(data, sharedMemory, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
|
||||
String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user