diff options
4 files changed, 208 insertions, 2 deletions
diff --git a/services/core/Android.bp b/services/core/Android.bp index 6d60164e3d0e..c6b80cb5b125 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -178,6 +178,7 @@ java_library_static { static_libs: [ "android.frameworks.vibrator-V1-java", // AIDL + "android.frameworks.devicestate-V1-java", // AIDL "android.hardware.authsecret-V1.0-java", "android.hardware.authsecret-V1-java", "android.hardware.boot-V1.0-java", // HIDL diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java index 8b9c664a31fd..251344395ae3 100644 --- a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java +++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java @@ -19,7 +19,16 @@ package com.android.server.devicestate; import static android.Manifest.permission.CONTROL_DEVICE_STATE; import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND; import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.frameworks.devicestate.DeviceStateConfiguration.DeviceStatePropertyValue.FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED; +import static android.frameworks.devicestate.DeviceStateConfiguration.DeviceStatePropertyValue.FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN; +import static android.frameworks.devicestate.DeviceStateConfiguration.DeviceStatePropertyValue.FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN; +import static android.frameworks.devicestate.DeviceStateConfiguration.DeviceStatePropertyValue.FEATURE_DUAL_DISPLAY; +import static android.frameworks.devicestate.DeviceStateConfiguration.DeviceStatePropertyValue.FEATURE_REAR_DISPLAY; +import static android.frameworks.devicestate.DeviceStateConfiguration.DeviceStatePropertyValue.FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY; +import static android.frameworks.devicestate.DeviceStateConfiguration.DeviceStatePropertyValue.FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY; +import static android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT; import static android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_REAR_DISPLAY; +import static android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY; import static android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY; import static android.hardware.devicestate.DeviceState.PROPERTY_POLICY_AVAILABLE_FOR_APP_REQUEST; import static android.hardware.devicestate.DeviceState.PROPERTY_POLICY_CANCEL_OVERRIDE_REQUESTS; @@ -44,6 +53,10 @@ import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.IProcessObserver; import android.content.Context; +import android.frameworks.devicestate.DeviceStateConfiguration; +import android.frameworks.devicestate.ErrorCode; +import android.frameworks.devicestate.IDeviceStateListener; +import android.frameworks.devicestate.IDeviceStateService; import android.hardware.devicestate.DeviceState; import android.hardware.devicestate.DeviceStateInfo; import android.hardware.devicestate.DeviceStateManager; @@ -56,9 +69,12 @@ import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; import android.os.ResultReceiver; +import android.os.ServiceManager; +import android.os.ServiceSpecificException; import android.os.ShellCallback; import android.os.SystemProperties; import android.os.Trace; +import android.util.LongSparseLongArray; import android.util.Slog; import android.util.SparseArray; @@ -82,6 +98,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.WeakHashMap; @@ -130,6 +147,8 @@ public final class DeviceStateManagerService extends SystemService { @NonNull private final BinderService mBinderService; @NonNull + private final HalService mHalService; + @NonNull private final OverrideRequestController mOverrideRequestController; @NonNull private final DeviceStateProviderListener mDeviceStateProviderListener; @@ -139,7 +158,7 @@ public final class DeviceStateManagerService extends SystemService { // All supported device states keyed by identifier. @GuardedBy("mLock") - private SparseArray<DeviceState> mDeviceStates = new SparseArray<>(); + private final SparseArray<DeviceState> mDeviceStates = new SparseArray<>(); // The current committed device state. Will be empty until the first device state provided by // the DeviceStateProvider is committed. @@ -177,7 +196,7 @@ public final class DeviceStateManagerService extends SystemService { @GuardedBy("mLock") private final SparseArray<ProcessRecord> mProcessRecords = new SparseArray<>(); - private Set<Integer> mDeviceStatesAvailableForAppRequests = new HashSet<>(); + private final Set<Integer> mDeviceStatesAvailableForAppRequests = new HashSet<>(); private Set<Integer> mFoldedDeviceStates = new HashSet<>(); @@ -259,6 +278,7 @@ public final class DeviceStateManagerService extends SystemService { mDeviceStateProviderListener = new DeviceStateProviderListener(); mDeviceStatePolicy.getDeviceStateProvider().setListener(mDeviceStateProviderListener); mBinderService = new BinderService(); + mHalService = new HalService(); mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class); mDeviceStateNotificationController = new DeviceStateNotificationController( context, mHandler, @@ -272,6 +292,10 @@ public final class DeviceStateManagerService extends SystemService { @Override public void onStart() { publishBinderService(Context.DEVICE_STATE_SERVICE, mBinderService); + String halServiceName = IDeviceStateService.DESCRIPTOR + "/default"; + if (ServiceManager.isDeclared(halServiceName)) { + publishBinderService(halServiceName, mHalService); + } publishLocalService(DeviceStateManagerInternal.class, new LocalService()); if (!Flags.deviceStatePropertyMigration()) { @@ -440,6 +464,11 @@ public final class DeviceStateManagerService extends SystemService { return mBinderService; } + @VisibleForTesting + IDeviceStateService getHalBinderService() { + return mHalService; + } + private void updateSupportedStates(DeviceState[] supportedDeviceStates, @DeviceStateProvider.SupportedStatesUpdatedReason int reason) { synchronized (mLock) { @@ -1282,6 +1311,124 @@ public final class DeviceStateManagerService extends SystemService { } } + private final class HalService extends IDeviceStateService.Stub { + private final LongSparseLongArray mPublicProperties = new LongSparseLongArray(); + public HalService() { + mPublicProperties.put( + DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED, + FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED); + mPublicProperties.put( + DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN, + FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN); + mPublicProperties.put( + DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN, + FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN); + mPublicProperties.put( + PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY, + FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY); + mPublicProperties.put( + PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY, + FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY); + mPublicProperties.put( + PROPERTY_FEATURE_REAR_DISPLAY, + FEATURE_REAR_DISPLAY); + mPublicProperties.put( + PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT, + FEATURE_DUAL_DISPLAY); + } + + private final class HalBinderCallback implements IDeviceStateManagerCallback { + private final IDeviceStateListener mListener; + + private HalBinderCallback(@NonNull IDeviceStateListener listener) { + mListener = listener; + } + + @Override + public void onDeviceStateInfoChanged(DeviceStateInfo info) throws RemoteException { + DeviceStateConfiguration config = new DeviceStateConfiguration(); + Set<Integer> systemProperties = new HashSet<>( + info.currentState.getConfiguration().getSystemProperties()); + Set<Integer> physicalProperties = new HashSet<>( + info.currentState.getConfiguration().getPhysicalProperties()); + config.deviceProperties = 0; + for (Integer prop : systemProperties) { + Long publicProperty = mPublicProperties.get(prop); + if (publicProperty != null) { + config.deviceProperties |= publicProperty.longValue(); + } + } + for (Integer prop : physicalProperties) { + Long publicProperty = mPublicProperties.get(prop); + if (publicProperty != null) { + config.deviceProperties |= publicProperty.longValue(); + } + } + mListener.onDeviceStateChanged(config); + } + + @Override + public void onRequestActive(IBinder token) { + //No-op + } + + @Override + public void onRequestCanceled(IBinder token) { + //No-op + } + + @Override + public IBinder asBinder() { + return mListener.asBinder(); + } + } + + @Override + public void registerListener(IDeviceStateListener listener) throws RemoteException { + if (listener == null) { + throw new ServiceSpecificException(ErrorCode.BAD_INPUT); + } + + final int callingPid = Binder.getCallingPid(); + final long token = Binder.clearCallingIdentity(); + try { + HalBinderCallback callback = new HalBinderCallback(listener); + DeviceStateInfo info = registerProcess(callingPid, callback); + if (info != null) { + callback.onDeviceStateInfoChanged(info); + } + } catch (SecurityException e) { + throw new ServiceSpecificException(ErrorCode.ALREADY_EXISTS); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override + public void unregisterListener(IDeviceStateListener listener) throws RemoteException { + final int callingPid = Binder.getCallingPid(); + + synchronized (mLock) { + if (mProcessRecords.contains(callingPid)) { + mProcessRecords.remove(callingPid); + return; + } + } + + throw new ServiceSpecificException(ErrorCode.BAD_INPUT); + } + + @Override + public int getInterfaceVersion() throws RemoteException { + return IDeviceStateService.VERSION; + } + + @Override + public String getInterfaceHash() throws RemoteException { + return IDeviceStateService.HASH; + } + } + /** Implementation of {@link IDeviceStateManager} published as a binder service. */ private final class BinderService extends IDeviceStateManager.Stub { diff --git a/services/manifest_services.xml b/services/manifest_services.xml index 114fe324f016..945720544991 100644 --- a/services/manifest_services.xml +++ b/services/manifest_services.xml @@ -4,4 +4,9 @@ <version>2</version> <fqname>IAltitudeService/default</fqname> </hal> + <hal format="aidl"> + <name>android.frameworks.devicestate</name> + <version>1</version> + <fqname>IDeviceStateService/default</fqname> + </hal> </manifest> diff --git a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java index ab5a5a9bf2fe..5127b2d11e44 100644 --- a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java @@ -24,9 +24,14 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertThrows; import android.content.Context; +import android.frameworks.devicestate.DeviceStateConfiguration; +import android.frameworks.devicestate.ErrorCode; +import android.frameworks.devicestate.IDeviceStateListener; +import android.frameworks.devicestate.IDeviceStateService; import android.hardware.devicestate.DeviceState; import android.hardware.devicestate.DeviceStateInfo; import android.hardware.devicestate.DeviceStateRequest; @@ -34,6 +39,7 @@ import android.hardware.devicestate.IDeviceStateManagerCallback; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; +import android.os.ServiceSpecificException; import android.platform.test.annotations.Presubmit; import android.platform.test.flag.junit.FlagsParameterization; import android.platform.test.flag.junit.SetFlagsRule; @@ -336,6 +342,53 @@ public final class DeviceStateManagerServiceTest { } @Test + public void halRegisterUnregisterCallback() throws RemoteException { + IDeviceStateService halService = mService.getHalBinderService(); + IDeviceStateListener halListener = new IDeviceStateListener.Stub() { + @Override + public void onDeviceStateChanged(DeviceStateConfiguration deviceState) { } + + @Override + public int getInterfaceVersion() { + return IDeviceStateListener.VERSION; + } + + @Override + public String getInterfaceHash() { + return IDeviceStateListener.HASH; + } + }; + + int errorCode = ErrorCode.OK; + try { + halService.unregisterListener(halListener); + } catch(ServiceSpecificException e) { + errorCode = e.errorCode; + } + assertEquals(errorCode, ErrorCode.BAD_INPUT); + + errorCode = ErrorCode.OK; + try { + halService.unregisterListener(null); + } catch(ServiceSpecificException e) { + errorCode = e.errorCode; + } + assertEquals(errorCode, ErrorCode.BAD_INPUT); + + halService.registerListener(halListener); + + errorCode = ErrorCode.OK; + try { + halService.registerListener(halListener); + } catch (ServiceSpecificException e) { + errorCode = e.errorCode; + } + assertEquals(errorCode, ErrorCode.ALREADY_EXISTS); + + halService.unregisterListener(halListener); + } + + @Test public void registerCallback() throws RemoteException { final TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback(); mService.getBinderService().registerCallback(callback); |