blob: cd48f5d527c1eed17e3be880599c73aa6ceabec9 [file] [log] [blame]
/*
* 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.internal.annotations.VisibleForTesting;
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.
*
* <p>The use of "Wearable" here is not the same as the Android Wear platform and should be treated
* separately. </p>
*/
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;
}
@VisibleForTesting
void provideDataStream(@UserIdInt int userId, ParcelFileDescriptor parcelFileDescriptor,
RemoteCallback callback) {
synchronized (mLock) {
final WearableSensingManagerPerUserService mService = getServiceForUserLocked(userId);
if (mService != null) {
mService.onProvideDataStream(parcelFileDescriptor, callback);
} else {
Slog.w(TAG, "Service not available.");
}
}
}
@VisibleForTesting
void provideData(@UserIdInt int userId, PersistableBundle data, SharedMemory sharedMemory,
RemoteCallback callback) {
synchronized (mLock) {
final WearableSensingManagerPerUserService mService = getServiceForUserLocked(userId);
if (mService != null) {
mService.onProvidedData(data, sharedMemory, callback);
} else {
Slog.w(TAG, "Service not available.");
}
}
}
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) {
new WearableSensingShellCommand(WearableSensingManagerService.this).exec(
this, in, out, err, args, callback, resultReceiver);
}
}
}