Merge "WearableSensing framework API for wearables."

This commit is contained in:
Charlie Wang
2022-11-24 02:18:37 +00:00
committed by Android (Google) Code Review
19 changed files with 1012 additions and 4 deletions

View File

@@ -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 {

View 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);
}

View File

@@ -0,0 +1,3 @@
charliewang@google.com
oni@google.com
volnov@google.com

View 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();
}
}
}

View File

@@ -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}.

View File

@@ -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.
*

View File

@@ -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);
}

View File

@@ -0,0 +1,3 @@
charliewang@google.com
oni@google.com
volnov@google.com

View 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);
}

View File

@@ -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

View File

@@ -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>

View File

@@ -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" />

View File

@@ -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:

View File

@@ -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,

View File

@@ -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;

View File

@@ -0,0 +1,3 @@
charliewang@google.com
oni@google.com
volnov@google.com

View File

@@ -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));
}
}

View File

@@ -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);
}
}
}

View File

@@ -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) {
}
}
}