Merge "WearableSensing framework API for wearables."
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";
|
||||
@@ -2876,6 +2878,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 {
|
||||
@@ -3130,6 +3147,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";
|
||||
@@ -10574,6 +10592,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";
|
||||
}
|
||||
|
||||
@@ -12356,6 +12375,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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6063,6 +6063,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}.
|
||||
|
||||
@@ -768,6 +768,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);
|
||||
}
|
||||
@@ -6763,6 +6763,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
|
||||
|
||||
@@ -4149,6 +4149,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:
|
||||
|
||||
@@ -940,6 +940,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")
|
||||
@@ -1713,6 +1714,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;
|
||||
@@ -2072,6 +2074,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.
|
||||
@@ -6067,6 +6072,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
|
||||
mConfiguratorPackage,
|
||||
mIncidentReportApproverPackage,
|
||||
mAmbientContextDetectionPackage,
|
||||
mWearableSensingPackage,
|
||||
mAppPredictionServicePackage,
|
||||
COMPANION_PACKAGE_NAME,
|
||||
mRetailDemoPackage,
|
||||
@@ -7105,6 +7111,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