From 641e2e6361af393697b6821da7e5b3317aa8553d Mon Sep 17 00:00:00 2001 From: Galia Peycheva Date: Tue, 18 Feb 2020 00:47:05 +0100 Subject: [PATCH] Create DreamManager System Server TestApi Bug: 141771803 Bug: 133216167 Test: atest DreamManagerServiceTests Test: make checkbuild Merged-In: I937061138bc8ccaf4475674f00331c3fe1c5a495 Change-Id: I937061138bc8ccaf4475674f00331c3fe1c5a495 (cherry picked from commit 4467c53c11c4ebfaf6681b82ec849192eb144a51) --- api/test-current.txt | 7 ++ core/java/android/app/DreamManager.java | 102 ++++++++++++++++++ .../android/app/SystemServiceRegistry.java | 7 ++ core/java/android/content/Context.java | 11 ++ .../android/service/dreams/IDreamManager.aidl | 6 +- .../settingslib/dream/DreamBackend.java | 4 +- .../server/dreams/DreamManagerService.java | 46 +++++--- 7 files changed, 167 insertions(+), 16 deletions(-) create mode 100644 core/java/android/app/DreamManager.java diff --git a/api/test-current.txt b/api/test-current.txt index d32c77f4cd254..1bcd2e1e9c6cb 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -412,6 +412,12 @@ package android.app { field public static final String COLUMN_MEDIASTORE_URI = "mediastore_uri"; } + public class DreamManager { + method @RequiresPermission("android.permission.WRITE_DREAM_STATE") public void setActiveDream(@NonNull android.content.ComponentName); + method @RequiresPermission("android.permission.WRITE_DREAM_STATE") public void startDream(@NonNull android.content.ComponentName); + method @RequiresPermission("android.permission.WRITE_DREAM_STATE") public void stopDream(); + } + public final class NotificationChannel implements android.os.Parcelable { method public int getOriginalImportance(); method public boolean isBlockableSystem(); @@ -791,6 +797,7 @@ package android.content { field public static final String BUGREPORT_SERVICE = "bugreport"; field public static final String CONTENT_CAPTURE_MANAGER_SERVICE = "content_capture"; field public static final String DEVICE_IDLE_CONTROLLER = "deviceidle"; + field public static final String DREAM_SERVICE = "dream"; field public static final String ETHERNET_SERVICE = "ethernet"; field public static final String NETWORK_STACK_SERVICE = "network_stack"; field public static final String PERMISSION_SERVICE = "permission"; diff --git a/core/java/android/app/DreamManager.java b/core/java/android/app/DreamManager.java new file mode 100644 index 0000000000000..fe13b8f26d789 --- /dev/null +++ b/core/java/android/app/DreamManager.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2020 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; + +import android.annotation.NonNull; +import android.annotation.RequiresPermission; +import android.annotation.SystemService; +import android.annotation.TestApi; +import android.annotation.UserHandleAware; +import android.content.ComponentName; +import android.content.Context; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.service.dreams.DreamService; +import android.service.dreams.IDreamManager; + +/** + * @hide + */ +@SystemService(Context.DREAM_SERVICE) +@TestApi +public class DreamManager { + private final IDreamManager mService; + private final Context mContext; + + /** + * @hide + */ + public DreamManager(Context context) throws ServiceManager.ServiceNotFoundException { + mService = IDreamManager.Stub.asInterface( + ServiceManager.getServiceOrThrow(DreamService.DREAM_SERVICE)); + mContext = context; + } + + /** + * Starts dream service with name "name". + * + *

This is only used for testing the dream service APIs. + * + * @hide + */ + @TestApi + @UserHandleAware + @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) + public void startDream(@NonNull ComponentName name) { + try { + mService.testDream(mContext.getUserId(), name); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + + /** + * Stops the dream service on the device if one is started. + * + *

This is only used for testing the dream service APIs. + * + * @hide + */ + @TestApi + @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) + public void stopDream() { + try { + mService.awaken(); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + + /** + * Sets the active dream on the device to be "dreamComponent". + * + *

This is only used for testing the dream service APIs. + * + * @hide + */ + @TestApi + @UserHandleAware + @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) + public void setActiveDream(@NonNull ComponentName dreamComponent) { + ComponentName[] dreams = {dreamComponent}; + try { + mService.setDreamComponentsForUser(mContext.getUserId(), dreams); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } +} diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 4369680e77819..ab73abbd75c0d 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -1334,6 +1334,13 @@ public final class SystemServiceRegistry { IBinder b = ServiceManager.getServiceOrThrow(Context.APP_INTEGRITY_SERVICE); return new AppIntegrityManager(IAppIntegrityManager.Stub.asInterface(b)); }}); + registerService(Context.DREAM_SERVICE, DreamManager.class, + new CachedServiceFetcher() { + @Override + public DreamManager createService(ContextImpl ctx) + throws ServiceNotFoundException { + return new DreamManager(ctx); + }}); sInitializing = true; try { diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index c6e84b7e46b05..536b6c33b1426 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -5156,6 +5156,17 @@ public abstract class Context { */ public static final String LIGHTS_SERVICE = "lights"; + /** + * Use with {@link #getSystemService(String)} to retrieve a + * {@link android.app.DreamManager} for controlling Dream states. + * + * @see #getSystemService(String) + + * @hide + */ + @TestApi + public static final String DREAM_SERVICE = "dream"; + /** * Determine whether the given permission is allowed for a particular * process and user ID running in the system. diff --git a/core/java/android/service/dreams/IDreamManager.aidl b/core/java/android/service/dreams/IDreamManager.aidl index d254ffdb69863..6496de3e15a03 100644 --- a/core/java/android/service/dreams/IDreamManager.aidl +++ b/core/java/android/service/dreams/IDreamManager.aidl @@ -31,12 +31,14 @@ interface IDreamManager { void setDreamComponents(in ComponentName[] componentNames); @UnsupportedAppUsage ComponentName[] getDreamComponents(); - ComponentName getDefaultDreamComponent(); - void testDream(in ComponentName componentName); + ComponentName getDefaultDreamComponentForUser(int userId); + void testDream(int userId, in ComponentName componentName); @UnsupportedAppUsage boolean isDreaming(); void finishSelf(in IBinder token, boolean immediate); void startDozing(in IBinder token, int screenState, int screenBrightness); void stopDozing(in IBinder token); void forceAmbientDisplayEnabled(boolean enabled); + ComponentName[] getDreamComponentsForUser(int userId); + void setDreamComponentsForUser(int userId, in ComponentName[] componentNames); } diff --git a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java index 3c0f6fe8ccbb3..57e680849fec3 100644 --- a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java +++ b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java @@ -136,7 +136,7 @@ public class DreamBackend { if (mDreamManager == null) return null; try { - return mDreamManager.getDefaultDreamComponent(); + return mDreamManager.getDefaultDreamComponentForUser(mContext.getUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed to get default dream", e); return null; @@ -269,7 +269,7 @@ public class DreamBackend { if (mDreamManager == null || dreamInfo == null || dreamInfo.componentName == null) return; try { - mDreamManager.testDream(dreamInfo.componentName); + mDreamManager.testDream(mContext.getUserId(), dreamInfo.componentName); } catch (RemoteException e) { Log.w(TAG, "Failed to preview " + dreamInfo, e); } diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java index a74be1357e302..eb0257e95b6c3 100644 --- a/services/core/java/com/android/server/dreams/DreamManagerService.java +++ b/services/core/java/com/android/server/dreams/DreamManagerService.java @@ -505,12 +505,18 @@ public final class DreamManagerService extends SystemService { @Override // Binder call public ComponentName[] getDreamComponents() { - checkPermission(android.Manifest.permission.READ_DREAM_STATE); + return getDreamComponentsForUser(UserHandle.getCallingUserId()); + } + + @Override // Binder call + public ComponentName[] getDreamComponentsForUser(int userId) { + checkPermission(android.Manifest.permission.READ_DREAM_STATE); + userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), + Binder.getCallingUid(), userId, false, true, "getDreamComponents", null); - final int userId = UserHandle.getCallingUserId(); final long ident = Binder.clearCallingIdentity(); try { - return getDreamComponentsForUser(userId); + return DreamManagerService.this.getDreamComponentsForUser(userId); } finally { Binder.restoreCallingIdentity(ident); } @@ -530,13 +536,28 @@ public final class DreamManagerService extends SystemService { } @Override // Binder call - public ComponentName getDefaultDreamComponent() { - checkPermission(android.Manifest.permission.READ_DREAM_STATE); + public void setDreamComponentsForUser(int userId, ComponentName[] componentNames) { + checkPermission(android.Manifest.permission.WRITE_DREAM_STATE); + userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), + Binder.getCallingUid(), userId, false, true, "setDreamComponents", null); - final int userId = UserHandle.getCallingUserId(); final long ident = Binder.clearCallingIdentity(); try { - return getDefaultDreamComponentForUser(userId); + DreamManagerService.this.setDreamComponentsForUser(userId, componentNames); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override // Binder call + public ComponentName getDefaultDreamComponentForUser(int userId) { + checkPermission(android.Manifest.permission.READ_DREAM_STATE); + userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), + Binder.getCallingUid(), userId, false, true, "getDefaultDreamComponent", null); + + final long ident = Binder.clearCallingIdentity(); + try { + return DreamManagerService.this.getDefaultDreamComponentForUser(userId); } finally { Binder.restoreCallingIdentity(ident); } @@ -567,24 +588,25 @@ public final class DreamManagerService extends SystemService { } @Override // Binder call - public void testDream(ComponentName dream) { + public void testDream(int userId, ComponentName dream) { if (dream == null) { throw new IllegalArgumentException("dream must not be null"); } checkPermission(android.Manifest.permission.WRITE_DREAM_STATE); + userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), + Binder.getCallingUid(), userId, false, true, "testDream", null); - final int callingUserId = UserHandle.getCallingUserId(); final int currentUserId = ActivityManager.getCurrentUser(); - if (callingUserId != currentUserId) { + if (userId != currentUserId) { // This check is inherently prone to races but at least it's something. Slog.w(TAG, "Aborted attempt to start a test dream while a different " - + " user is active: callingUserId=" + callingUserId + + " user is active: userId=" + userId + ", currentUserId=" + currentUserId); return; } final long ident = Binder.clearCallingIdentity(); try { - testDreamInternal(dream, callingUserId); + testDreamInternal(dream, userId); } finally { Binder.restoreCallingIdentity(ident); }