From ac20732c925f3c3f3b6fe3c2ebb8bfa1b1f2d6f0 Mon Sep 17 00:00:00 2001 From: Charlie Wang Date: Mon, 28 Nov 2022 11:05:43 -0800 Subject: [PATCH] Enable WearableSensingService. This change includes: 1. Enabling WearableSensingManager to be retrievable. 2. Starts WearableSensingService from system server. 3. Introduces WearableSensingShellComamnd for testing. Bug: 249135378, 244181656 Test: Builds. Ignore-AOSP-First: to prevent new feature leak. Change-Id: I4ffaac37c0fe8874ae8b0ae6fec086e4cd27b2f1 --- .../android/app/SystemServiceRegistry.java | 13 ++ .../WearableSensingManagerService.java | 28 +++ .../wearable/WearableSensingShellCommand.java | 212 ++++++++++++++++++ .../java/com/android/server/SystemServer.java | 8 + 4 files changed, 261 insertions(+) create mode 100644 services/core/java/com/android/server/wearable/WearableSensingShellCommand.java diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index e54a0841dd26f..9a731d0e839f3 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -51,6 +51,8 @@ import android.app.usage.StorageStatsManager; import android.app.usage.UsageStatsManager; import android.app.wallpapereffectsgeneration.IWallpaperEffectsGenerationManager; import android.app.wallpapereffectsgeneration.WallpaperEffectsGenerationManager; +import android.app.wearable.IWearableSensingManager; +import android.app.wearable.WearableSensingManager; import android.apphibernation.AppHibernationManager; import android.appwidget.AppWidgetManager; import android.bluetooth.BluetoothFrameworkInitializer; @@ -1540,6 +1542,17 @@ public final class SystemServiceRegistry { IAmbientContextManager.Stub.asInterface(iBinder); return new AmbientContextManager(ctx.getOuterContext(), manager); }}); + registerService(Context.WEARABLE_SENSING_SERVICE, WearableSensingManager.class, + new CachedServiceFetcher() { + @Override + public WearableSensingManager createService(ContextImpl ctx) + throws ServiceNotFoundException { + IBinder iBinder = ServiceManager.getServiceOrThrow( + Context.WEARABLE_SENSING_SERVICE); + IWearableSensingManager manager = + IWearableSensingManager.Stub.asInterface(iBinder); + return new WearableSensingManager(ctx.getOuterContext(), manager); + }}); sInitializing = true; try { diff --git a/services/core/java/com/android/server/wearable/WearableSensingManagerService.java b/services/core/java/com/android/server/wearable/WearableSensingManagerService.java index e155a06901286..707d00449ef57 100644 --- a/services/core/java/com/android/server/wearable/WearableSensingManagerService.java +++ b/services/core/java/com/android/server/wearable/WearableSensingManagerService.java @@ -161,6 +161,32 @@ public class WearableSensingManagerService extends return null; } + // Used in testing. + 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."); + } + } + } + + // Used in testing. + 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()); @@ -205,6 +231,8 @@ public class WearableSensingManagerService extends @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); } } } diff --git a/services/core/java/com/android/server/wearable/WearableSensingShellCommand.java b/services/core/java/com/android/server/wearable/WearableSensingShellCommand.java new file mode 100644 index 0000000000000..842bccbe0847e --- /dev/null +++ b/services/core/java/com/android/server/wearable/WearableSensingShellCommand.java @@ -0,0 +1,212 @@ +/* + * 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.annotation.NonNull; +import android.app.wearable.WearableSensingManager; +import android.content.ComponentName; +import android.os.Binder; +import android.os.ParcelFileDescriptor; +import android.os.PersistableBundle; +import android.os.RemoteCallback; +import android.os.ShellCommand; +import android.util.Slog; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; + +final class WearableSensingShellCommand extends ShellCommand { + private static final String TAG = WearableSensingShellCommand.class.getSimpleName(); + + static final TestableCallbackInternal sTestableCallbackInternal = + new TestableCallbackInternal(); + + @NonNull + private final WearableSensingManagerService mService; + + private static ParcelFileDescriptor[] sPipe; + + WearableSensingShellCommand(@NonNull WearableSensingManagerService service) { + mService = service; + } + + /** Callbacks for WearableSensingService results used internally for testing. */ + static class TestableCallbackInternal { + private int mLastStatus; + + public int getLastStatus() { + return mLastStatus; + } + + @NonNull + private RemoteCallback createRemoteStatusCallback() { + return new RemoteCallback(result -> { + int status = result.getInt(WearableSensingManager.STATUS_RESPONSE_BUNDLE_KEY); + final long token = Binder.clearCallingIdentity(); + try { + mLastStatus = status; + } finally { + Binder.restoreCallingIdentity(token); + } + }); + } + } + + @Override + public int onCommand(String cmd) { + if (cmd == null) { + return handleDefaultCommands(cmd); + } + + switch (cmd) { + case "create-data-stream": + return createDataStream(); + case "destroy-data-stream": + return destroyDataStream(); + case "provide-data-stream": + return provideDataStream(); + case "write-to-data-stream": + return writeToDataStream(); + case "provide-data": + return provideData(); + case "get-last-status-code": + return getLastStatusCode(); + case "get-bound-package": + return getBoundPackageName(); + case "set-temporary-service": + return setTemporaryService(); + default: + return handleDefaultCommands(cmd); + } + } + + @Override + public void onHelp() { + PrintWriter pw = getOutPrintWriter(); + pw.println("WearableSensingCommands commands: "); + pw.println(" help"); + pw.println(" Print this help text."); + pw.println(); + pw.println(" create-data-stream: Creates a data stream to be provided."); + pw.println(" destroy-data-stream: Destroys a data stream if one was previously created."); + pw.println(" provide-data-stream USER_ID: " + + "Provides data stream to WearableSensingService."); + pw.println(" write-to-data-stream STRING: writes string to data stream."); + pw.println(" provide-data USER_ID KEY INTEGER: provide integer as data with key."); + pw.println(" get-last-status-code: Prints the latest request status code."); + pw.println(" get-bound-package USER_ID:" + + " Print the bound package that implements the service."); + pw.println(" set-temporary-service USER_ID [PACKAGE_NAME] [COMPONENT_NAME DURATION]"); + pw.println(" Temporarily (for DURATION ms) changes the service implementation."); + pw.println(" To reset, call with just the USER_ID argument."); + } + + private int createDataStream() { + Slog.d(TAG, "createDataStream"); + try { + sPipe = ParcelFileDescriptor.createPipe(); + } catch (IOException e) { + Slog.d(TAG, "Failed to createDataStream.", e); + } + return 0; + } + + private int destroyDataStream() { + Slog.d(TAG, "destroyDataStream"); + try { + if (sPipe != null) { + sPipe[0].close(); + sPipe[1].close(); + } + } catch (IOException e) { + Slog.d(TAG, "Failed to destroyDataStream.", e); + } + return 0; + } + + private int provideDataStream() { + Slog.d(TAG, "provideDataStream"); + if (sPipe != null) { + final int userId = Integer.parseInt(getNextArgRequired()); + mService.provideDataStream(userId, sPipe[0], + sTestableCallbackInternal.createRemoteStatusCallback()); + } + return 0; + } + + private int writeToDataStream() { + Slog.d(TAG, "writeToDataStream"); + if (sPipe != null) { + final String value = getNextArgRequired(); + try { + ParcelFileDescriptor writePipe = sPipe[1].dup(); + OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(writePipe); + os.write(value.getBytes()); + } catch (IOException e) { + Slog.d(TAG, "Failed to writeToDataStream.", e); + } + } + return 0; + } + + private int provideData() { + Slog.d(TAG, "provideData"); + final int userId = Integer.parseInt(getNextArgRequired()); + final String key = getNextArgRequired(); + final int value = Integer.parseInt(getNextArgRequired()); + PersistableBundle data = new PersistableBundle(); + data.putInt(key, value); + + mService.provideData(userId, data, null, + sTestableCallbackInternal.createRemoteStatusCallback()); + return 0; + } + + private int getLastStatusCode() { + Slog.d(TAG, "getLastStatusCode"); + final PrintWriter resultPrinter = getOutPrintWriter(); + int lastStatus = sTestableCallbackInternal.getLastStatus(); + resultPrinter.println(lastStatus); + return 0; + } + + private int setTemporaryService() { + final PrintWriter out = getOutPrintWriter(); + final int userId = Integer.parseInt(getNextArgRequired()); + final String serviceName = getNextArg(); + if (serviceName == null) { + mService.resetTemporaryService(userId); + out.println("WearableSensingManagerService temporary reset. "); + return 0; + } + + final int duration = Integer.parseInt(getNextArgRequired()); + mService.setTemporaryService(userId, serviceName, duration); + out.println("WearableSensingService temporarily set to " + serviceName + + " for " + duration + "ms"); + return 0; + } + + private int getBoundPackageName() { + final PrintWriter resultPrinter = getOutPrintWriter(); + final int userId = Integer.parseInt(getNextArgRequired()); + final ComponentName componentName = mService.getComponentName(userId); + resultPrinter.println(componentName == null ? "" : componentName.getPackageName()); + return 0; + } +} diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index c346b2f52dc2d..e96eff21bcc5a 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -211,6 +211,7 @@ import com.android.server.usage.UsageStatsService; import com.android.server.utils.TimingsTraceAndSlog; import com.android.server.vibrator.VibratorManagerService; import com.android.server.vr.VrManagerService; +import com.android.server.wearable.WearableSensingManagerService; import com.android.server.webkit.WebViewUpdateService; import com.android.server.wm.ActivityTaskManagerService; import com.android.server.wm.WindowManagerGlobalLock; @@ -1830,6 +1831,7 @@ public final class SystemServer implements Dumpable { startSystemCaptionsManagerService(context, t); startTextToSpeechManagerService(context, t); startAmbientContextService(t); + startWearableSensingService(t); // System Speech Recognition Service t.traceBegin("StartSpeechRecognitionManagerService"); @@ -3170,6 +3172,12 @@ public final class SystemServer implements Dumpable { t.traceEnd(); } + private void startWearableSensingService(@NonNull TimingsTraceAndSlog t) { + t.traceBegin("startWearableSensingService"); + mSystemServiceManager.startService(WearableSensingManagerService.class); + t.traceEnd(); + } + private static void startSystemUi(Context context, WindowManagerService windowManager) { PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class); Intent intent = new Intent();