From 8dd20ce557958ee409727d3c76b46522080bb570 Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Thu, 22 Feb 2024 17:42:46 +0000 Subject: Revert^2 "uwb(tests): More tests for hw idle feature" 6bf3ea1f5513db80183978f9535579bc8b0b4766 Merged-In: I742c1548c9ed129eb30e63b5fcb01eaa22668310 Change-Id: Ie24e6f12e4fd4c522eb23deabafac1ba06772bbb --- framework/java/android/uwb/IUwbAdapter.aidl | 3 +- framework/java/android/uwb/UwbManager.java | 4 +- .../com/android/server/uwb/UwbServiceCore.java | 106 ++++++++++++++++----- .../com/android/server/uwb/UwbServiceImpl.java | 6 +- .../com/android/server/uwb/UwbShellCommand.java | 4 +- .../tests/src/android/uwb/cts/UwbManagerTest.java | 59 +++++++++--- 6 files changed, 138 insertions(+), 44 deletions(-) diff --git a/framework/java/android/uwb/IUwbAdapter.aidl b/framework/java/android/uwb/IUwbAdapter.aidl index 287dc6cf..8574e4bd 100644 --- a/framework/java/android/uwb/IUwbAdapter.aidl +++ b/framework/java/android/uwb/IUwbAdapter.aidl @@ -17,6 +17,7 @@ package android.uwb; import android.content.AttributionSource; +import android.os.IBinder; import android.os.PersistableBundle; import android.uwb.IUwbAdapterStateCallbacks; import android.uwb.IUwbAdfProvisionStateCallbacks; @@ -301,7 +302,7 @@ interface IUwbAdapter { int getAdapterState(); boolean isHwIdleTurnOffEnabled(); - void requestHwEnabled(boolean enabled, in AttributionSource attributionSource); + void requestHwEnabled(boolean enabled, in AttributionSource attributionSource, IBinder binder); boolean isHwEnableRequested(in AttributionSource attributionSource); /** diff --git a/framework/java/android/uwb/UwbManager.java b/framework/java/android/uwb/UwbManager.java index d19ff9bb..704a548e 100644 --- a/framework/java/android/uwb/UwbManager.java +++ b/framework/java/android/uwb/UwbManager.java @@ -816,7 +816,9 @@ public final class UwbManager { @RequiresPermission(permission.UWB_PRIVILEGED) public void requestUwbHwEnabled(boolean enabled) { try { - mUwbAdapter.requestHwEnabled(enabled, mContext.getAttributionSource()); + mUwbAdapter.requestHwEnabled( + enabled, mContext.getAttributionSource(), + new Binder(mContext.getPackageName())); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/service/java/com/android/server/uwb/UwbServiceCore.java b/service/java/com/android/server/uwb/UwbServiceCore.java index eea1cab0..8098bd55 100644 --- a/service/java/com/android/server/uwb/UwbServiceCore.java +++ b/service/java/com/android/server/uwb/UwbServiceCore.java @@ -25,6 +25,7 @@ import android.annotation.NonNull; import android.content.AttributionSource; import android.content.Context; import android.os.Handler; +import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.PersistableBundle; @@ -84,6 +85,7 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.HashMap; import java.util.Map; +import java.util.NoSuchElementException; import java.util.Objects; import java.util.Optional; import java.util.Set; @@ -149,11 +151,32 @@ public class UwbServiceCore implements INativeUwbManager.DeviceNotification, * to remove the check for token since we want to uniquely identify client (not different binder * tokens* from the same client). */ - private class AttributionSourceHolder { + private class AttributionSourceHolder implements IBinder.DeathRecipient { private final AttributionSource mAttributionSource; + private final IBinder mBinder; - AttributionSourceHolder(AttributionSource attributionSource) { + AttributionSourceHolder(AttributionSource attributionSource, IBinder binder) { mAttributionSource = attributionSource; + mBinder = binder; + } + + public AttributionSource getAttributionSource() { + return mAttributionSource; + } + + public void linkToDeath() { + try { + mBinder.linkToDeath(this, 0); + } catch (RemoteException e) { + Log.e(TAG, "Failed to register for death recipient for " + + mAttributionSource); + } + } + + public void unlinkToDeath() { + try { + mBinder.unlinkToDeath(this, 0); + } catch (NoSuchElementException e) { } } @Override @@ -180,6 +203,11 @@ public class UwbServiceCore implements INativeUwbManager.DeviceNotification, return mAttributionSource.toString(); } + @Override + public void binderDied() { + Log.i(TAG, "binderDied : reset hw enable for " + this); + mUwbClientHwState.setEnabled(this, false); + } } /** @@ -188,12 +216,35 @@ public class UwbServiceCore implements INativeUwbManager.DeviceNotification, private class UwbClientHwState { private final Map mMap = new HashMap<>(); - public void setEnabled(AttributionSource attributionSource, boolean enable) { - mMap.put(new AttributionSourceHolder(attributionSource), Boolean.valueOf(enable)); + public void setEnabled(AttributionSourceHolder attributionSourceHolder, boolean enable) { + Boolean prevValue = mMap.put(attributionSourceHolder, Boolean.valueOf(enable)); + if (prevValue == null) prevValue = false; + // If enabling, add link to death. + if (!prevValue && enable) { + attributionSourceHolder.linkToDeath(); + } + // If disabling, remove link to death. + if (prevValue && !enable) { + attributionSourceHolder.unlinkToDeath(); + } } - public boolean isEnabled(AttributionSource attributionSource) { - return mMap.getOrDefault(new AttributionSourceHolder(attributionSource), false); + /** + * We use AttributionSourceHolder to linkToDeath, so avoid creating duplicate objects in the + * map for the same client. + */ + public AttributionSourceHolder getOrCreate( + AttributionSource attributionSource, IBinder binder) { + for (AttributionSourceHolder k : mMap.keySet()) { + if (Objects.equals(k.getAttributionSource(), attributionSource)) { + return k; + } + } + return new AttributionSourceHolder(attributionSource, binder); + } + + public boolean isEnabled(AttributionSourceHolder attributionSourceHolder) { + return mMap.getOrDefault(attributionSourceHolder, false); } /** @@ -875,29 +926,32 @@ public class UwbServiceCore implements INativeUwbManager.DeviceNotification, } public synchronized void requestHwEnabled( - boolean enabled, AttributionSource attributionSource) { + boolean enabled, AttributionSource attributionSource, IBinder binder) { int task = enabled ? TASK_HW_ENABLE : TASK_HW_DISABLE; - - if (enabled && mUwbClientHwState.isEnabled(attributionSource)) { + AttributionSourceHolder attributionSourceHolder = + mUwbClientHwState.getOrCreate(attributionSource, binder); + if (enabled && mUwbClientHwState.isEnabled(attributionSourceHolder)) { Log.w(TAG, "Uwb hardware is already enabled by " + attributionSource); - } else if (!enabled && !mUwbClientHwState.isEnabled(attributionSource)) { + } else if (!enabled && !mUwbClientHwState.isEnabled(attributionSourceHolder)) { Log.w(TAG, "Uwb hardware is already disabled by " + attributionSource); } - - mUwbTask.execute(task, attributionSource); + mUwbTask.execute(task, attributionSourceHolder); } - private void updateHwState(AttributionSource attributionSource, boolean enable) { - Log.d(TAG, "updateHwState(): state=" + enable + ", attributionSource=" + attributionSource); + private void updateHwState(AttributionSourceHolder attributionSourceHolder, boolean enable) { + Log.d(TAG, "updateHwState(): state=" + enable + + ", attributionSource=" + attributionSourceHolder); synchronized (UwbServiceCore.this) { - mUwbClientHwState.setEnabled(attributionSource, enable); + mUwbClientHwState.setEnabled(attributionSourceHolder, enable); Log.d(TAG, "mUwbClientHwState= " + mUwbClientHwState); } } public boolean isHwEnableRequested(AttributionSource attributionSource) { synchronized (UwbServiceCore.this) { - return mUwbClientHwState.isEnabled(attributionSource); + AttributionSourceHolder attributionSourceHolder = + mUwbClientHwState.getOrCreate(attributionSource, null); + return mUwbClientHwState.isEnabled(attributionSourceHolder); } } @@ -1002,11 +1056,11 @@ public class UwbServiceCore implements INativeUwbManager.DeviceNotification, break; case TASK_HW_ENABLE: - handleHwEnable((AttributionSource) msg.obj); + handleHwEnable((AttributionSourceHolder) msg.obj); break; case TASK_HW_DISABLE: - handleHwDisable((AttributionSource) msg.obj); + handleHwDisable((AttributionSourceHolder) msg.obj); break; case TASK_RESTART: @@ -1199,26 +1253,26 @@ public class UwbServiceCore implements INativeUwbManager.DeviceNotification, deInitializeHw(); } - private void handleHwEnable(AttributionSource attributionSource) { - if (mUwbClientHwState.isEnabled(attributionSource)) { - Log.i(TAG, "UWB hardware is already enabled by " + attributionSource); + private void handleHwEnable(AttributionSourceHolder attributionSourceHolder) { + if (mUwbClientHwState.isEnabled(attributionSourceHolder)) { + Log.i(TAG, "UWB hardware is already enabled by " + attributionSourceHolder); return; } boolean prevShouldHwBeEnabled = mUwbClientHwState.shouldHwBeEnabled(); - updateHwState(attributionSource, true); + updateHwState(attributionSourceHolder, true); if (!prevShouldHwBeEnabled && mUwbClientHwState.shouldHwBeEnabled()) { Log.i(TAG, "UWB Hw requested, enabling"); initializeHw(); } } - private void handleHwDisable(AttributionSource attributionSource) { - if (!mUwbClientHwState.isEnabled(attributionSource)) { - Log.i(TAG, "UWB hardware is already disabled by " + attributionSource); + private void handleHwDisable(AttributionSourceHolder attributionSourceHolder) { + if (!mUwbClientHwState.isEnabled(attributionSourceHolder)) { + Log.i(TAG, "UWB hardware is already disabled by " + attributionSourceHolder); return; } boolean prevShouldHwBeEnabled = mUwbClientHwState.shouldHwBeEnabled(); - updateHwState(attributionSource, false); + updateHwState(attributionSourceHolder, false); if (prevShouldHwBeEnabled && !mUwbClientHwState.shouldHwBeEnabled()) { Log.i(TAG, "UWB Hw not requested, disabling"); deInitializeHw(); diff --git a/service/java/com/android/server/uwb/UwbServiceImpl.java b/service/java/com/android/server/uwb/UwbServiceImpl.java index a4e5ada0..a8306909 100644 --- a/service/java/com/android/server/uwb/UwbServiceImpl.java +++ b/service/java/com/android/server/uwb/UwbServiceImpl.java @@ -27,6 +27,7 @@ import android.content.IntentFilter; import android.database.ContentObserver; import android.net.Uri; import android.os.Binder; +import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.PersistableBundle; import android.os.Process; @@ -433,13 +434,14 @@ public class UwbServiceImpl extends IUwbAdapter.Stub { } @Override - public synchronized void requestHwEnabled(boolean enabled, AttributionSource attributionSource) + public synchronized void requestHwEnabled( + boolean enabled, AttributionSource attributionSource, IBinder binder) throws RemoteException { enforceUwbPrivilegedPermission(); if (!mUwbInjector.getDeviceConfigFacade().isHwIdleTurnOffEnabled()) { throw new IllegalStateException("Hw Idle turn off not enabled"); } - mUwbServiceCore.requestHwEnabled(enabled, attributionSource); + mUwbServiceCore.requestHwEnabled(enabled, attributionSource, binder); } @Override diff --git a/service/java/com/android/server/uwb/UwbShellCommand.java b/service/java/com/android/server/uwb/UwbShellCommand.java index f850ec15..b3e107f9 100644 --- a/service/java/com/android/server/uwb/UwbShellCommand.java +++ b/service/java/com/android/server/uwb/UwbShellCommand.java @@ -1262,7 +1262,7 @@ public class UwbShellCommand extends BasicShellCommandHandler { Process.SHELL_UID) .setPackageName(SHELL_PACKAGE_NAME) .build(); - mUwbService.requestHwEnabled(true, attributionSource); + mUwbService.requestHwEnabled(true, attributionSource, new Binder()); return 0; } case "disable-uwb-hw": { @@ -1270,7 +1270,7 @@ public class UwbShellCommand extends BasicShellCommandHandler { Process.SHELL_UID) .setPackageName(SHELL_PACKAGE_NAME) .build(); - mUwbService.requestHwEnabled(false, attributionSource); + mUwbService.requestHwEnabled(false, attributionSource, new Binder()); return 0; } case "start-dl-tdoa-ranging-session": diff --git a/tests/cts/tests/src/android/uwb/cts/UwbManagerTest.java b/tests/cts/tests/src/android/uwb/cts/UwbManagerTest.java index f67dc021..38edd886 100644 --- a/tests/cts/tests/src/android/uwb/cts/UwbManagerTest.java +++ b/tests/cts/tests/src/android/uwb/cts/UwbManagerTest.java @@ -134,7 +134,7 @@ public class UwbManagerTest { } if (mUwbManager.isUwbHwIdleTurnOffEnabled()) { // If HW idle mode is turned on, vote for the UWB hardware for tests to pass. - requestUwbHwEnabledAndWaitForCompletion(true); + requestUwbHwEnabledAndWaitForCompletion(true, mUwbManager, true); } mDefaultChipId = mUwbManager.getDefaultChipId(); } finally { @@ -150,7 +150,7 @@ public class UwbManagerTest { uiAutomation.adoptShellPermissionIdentity(); if (mUwbManager.isUwbHwIdleTurnOffEnabled()) { // If HW idle mode is turned on, reset vote for the UWB hardware. - requestUwbHwEnabledAndWaitForCompletion(false); + requestUwbHwEnabledAndWaitForCompletion(false, mUwbManager, false); } mDefaultChipId = mUwbManager.getDefaultChipId(); } finally { @@ -1491,7 +1491,7 @@ public class UwbManagerTest { }); } - private class AdapterStateCallback implements UwbManager.AdapterStateCallback { + private static class AdapterStateCallback implements UwbManager.AdapterStateCallback { private final CountDownLatch mCountDownLatch; private final Integer mWaitForState; public int state; @@ -1994,21 +1994,30 @@ public class UwbManagerTest { null)); } + private UwbManager createUwbManagerWithAttrTag(String attributionTag) { + Context contextWithAttrTag = mContext.createContext( + new ContextParams.Builder() + .setAttributionTag(attributionTag) + .build() + ); + return contextWithAttrTag.getSystemService(UwbManager.class); + } + // Should be invoked with shell permissions. - private void requestUwbHwEnabledAndWaitForCompletion(boolean enabled) throws Exception { + private static void requestUwbHwEnabledAndWaitForCompletion(boolean enabled, + UwbManager uwbManager, boolean expectAdapterEnable) throws Exception { CountDownLatch countDownLatch = new CountDownLatch(1); - int adapterState = enabled ? STATE_ENABLED_INACTIVE : STATE_ENABLED_HW_IDLE; + int adapterState = expectAdapterEnable ? STATE_ENABLED_INACTIVE : STATE_ENABLED_HW_IDLE; AdapterStateCallback adapterStateCallback = new AdapterStateCallback(countDownLatch, adapterState); try { - mUwbManager.registerAdapterStateCallback( + uwbManager.registerAdapterStateCallback( Executors.newSingleThreadExecutor(), adapterStateCallback); - mUwbManager.requestUwbHwEnabled(enabled); + uwbManager.requestUwbHwEnabled(enabled); assertThat(countDownLatch.await(2, TimeUnit.SECONDS)).isTrue(); - assertThat(mUwbManager.isUwbHwEnabled()).isEqualTo(enabled); assertThat(adapterStateCallback.state).isEqualTo(adapterState); } finally { - mUwbManager.unregisterAdapterStateCallback(adapterStateCallback); + uwbManager.unregisterAdapterStateCallback(adapterStateCallback); } } @@ -2021,12 +2030,38 @@ public class UwbManagerTest { try { // Needs UWB_PRIVILEGED permission which is held by shell. uiAutomation.adoptShellPermissionIdentity(); - assertThat(mUwbManager.isUwbHwEnabled()).isTrue(); + assertThat(mUwbManager.isUwbHwEnableRequested()).isEqualTo(true); assertThat(mUwbManager.getAdapterState()).isEqualTo(STATE_ENABLED_INACTIVE); // Toggle the HW state on & off. - requestUwbHwEnabledAndWaitForCompletion(false); - requestUwbHwEnabledAndWaitForCompletion(true); + requestUwbHwEnabledAndWaitForCompletion(false, mUwbManager, false); + requestUwbHwEnabledAndWaitForCompletion(true, mUwbManager, true); + } finally { + uiAutomation.dropShellPermissionIdentity(); + } + } + + @Test + @CddTest(requirements = {"7.3.13/C-1-1,C-1-2,C-1-4"}) + @RequiresFlagsEnabled("com.android.uwb.flags.hw_state") + public void testUwbHwStateToggleMultipleClients() throws Exception { + assumeTrue(mUwbManager.isUwbHwIdleTurnOffEnabled()); + UiAutomation uiAutomation = getInstrumentation().getUiAutomation(); + UwbManager uwbManagerWithAttrTag1 = createUwbManagerWithAttrTag("tag1"); + UwbManager uwbManagerWithAttrTag2 = createUwbManagerWithAttrTag("tag2"); + try { + // Needs UWB_PRIVILEGED permission which is held by shell. + uiAutomation.adoptShellPermissionIdentity(); + // First remove the vote from the test setup + requestUwbHwEnabledAndWaitForCompletion(false, mUwbManager, false); + + // Toggle the HW state on & off. + requestUwbHwEnabledAndWaitForCompletion(true, uwbManagerWithAttrTag1, true); + requestUwbHwEnabledAndWaitForCompletion(true, uwbManagerWithAttrTag2, true); + requestUwbHwEnabledAndWaitForCompletion(false, uwbManagerWithAttrTag1, true); + requestUwbHwEnabledAndWaitForCompletion(false, uwbManagerWithAttrTag2, false); } finally { + // Reset back to vote as expected by the setup. + requestUwbHwEnabledAndWaitForCompletion(true, mUwbManager, true); uiAutomation.dropShellPermissionIdentity(); } } -- cgit v1.2.3