diff --git a/services/Android.bp b/services/Android.bp index a2d6beb41d293..82d9b3e51c2d9 100644 --- a/services/Android.bp +++ b/services/Android.bp @@ -68,7 +68,6 @@ filegroup { ":services.texttospeech-sources", ":services.usage-sources", ":services.usb-sources", - ":services.uwb-sources", ":services.voiceinteraction-sources", ":services.wifi-sources", ], @@ -122,7 +121,6 @@ java_library { "services.texttospeech", "services.usage", "services.usb", - "services.uwb", "services.voiceinteraction", "services.wifi", "service-blobstore", diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 00100158e7edd..46adb32ff1036 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -384,6 +384,8 @@ public final class SystemServer implements Dumpable { private static final String ROLE_SERVICE_CLASS = "com.android.role.RoleService"; private static final String GAME_MANAGER_SERVICE_CLASS = "com.android.server.app.GameManagerService$Lifecycle"; + private static final String UWB_APEX_SERVICE_JAR_PATH = + "/apex/com.android.uwb/javalib/service-uwb.jar"; private static final String UWB_SERVICE_CLASS = "com.android.server.uwb.UwbService"; private static final String TETHERING_CONNECTOR_CLASS = "android.net.ITetheringConnector"; @@ -2651,7 +2653,7 @@ public final class SystemServer implements Dumpable { if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_UWB)) { t.traceBegin("UwbService"); - mSystemServiceManager.startService(UWB_SERVICE_CLASS); + mSystemServiceManager.startServiceFromJar(UWB_SERVICE_CLASS, UWB_APEX_SERVICE_JAR_PATH); t.traceEnd(); } diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp index d1afa1a997bf0..c19155f517433 100644 --- a/services/tests/servicestests/Android.bp +++ b/services/tests/servicestests/Android.bp @@ -37,7 +37,6 @@ android_test { "services.net", "services.people", "services.usage", - "services.uwb", "guava", "guava-android-testlib", "androidx.test.core", diff --git a/services/tests/servicestests/src/com/android/server/uwb/OWNERS b/services/tests/servicestests/src/com/android/server/uwb/OWNERS deleted file mode 100644 index c31a2f1ed3bc5..0000000000000 --- a/services/tests/servicestests/src/com/android/server/uwb/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include platform/frameworks/base:/core/java/android/uwb/OWNERS diff --git a/services/tests/servicestests/src/com/android/server/uwb/UwbServiceImplTest.java b/services/tests/servicestests/src/com/android/server/uwb/UwbServiceImplTest.java deleted file mode 100644 index 11554c7a7dc55..0000000000000 --- a/services/tests/servicestests/src/com/android/server/uwb/UwbServiceImplTest.java +++ /dev/null @@ -1,365 +0,0 @@ -/* - * Copyright (C) 2021 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.uwb; - -import static android.Manifest.permission.UWB_PRIVILEGED; - -import static com.google.common.truth.Truth.assertThat; - -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.clearInvocations; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.content.AttributionSource; -import android.content.Context; -import android.os.IBinder; -import android.os.PersistableBundle; -import android.platform.test.annotations.Presubmit; -import android.test.suitebuilder.annotation.SmallTest; -import android.uwb.IUwbAdapter; -import android.uwb.IUwbAdapterStateCallbacks; -import android.uwb.IUwbRangingCallbacks; -import android.uwb.RangingReport; -import android.uwb.RangingSession; -import android.uwb.SessionHandle; - -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -/** - * Tests for {@link UwbServiceImpl}. - */ -@RunWith(AndroidJUnit4.class) -@SmallTest -@Presubmit -public class UwbServiceImplTest { - private static final int UID = 343453; - private static final String PACKAGE_NAME = "com.uwb.test"; - private static final AttributionSource ATTRIBUTION_SOURCE = - new AttributionSource.Builder(UID).setPackageName(PACKAGE_NAME).build(); - - @Mock private IUwbAdapter mVendorService; - @Mock private IBinder mVendorServiceBinder; - @Mock private Context mContext; - @Mock private UwbInjector mUwbInjector; - @Captor private ArgumentCaptor mRangingCbCaptor; - @Captor private ArgumentCaptor mClientDeathCaptor; - @Captor private ArgumentCaptor mVendorServiceDeathCaptor; - - private UwbServiceImpl mUwbServiceImpl; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - when(mUwbInjector.getVendorService()).thenReturn(mVendorService); - when(mUwbInjector.checkUwbRangingPermissionForDataDelivery(any(), any())).thenReturn(true); - when(mVendorService.asBinder()).thenReturn(mVendorServiceBinder); - mUwbServiceImpl = new UwbServiceImpl(mContext, mUwbInjector); - } - - @Test - public void testApiCallThrowsIllegalStateExceptionIfVendorServiceNotFound() throws Exception { - when(mUwbInjector.getVendorService()).thenReturn(null); - - final IUwbAdapterStateCallbacks cb = mock(IUwbAdapterStateCallbacks.class); - try { - mUwbServiceImpl.registerAdapterStateCallbacks(cb); - fail(); - } catch (IllegalStateException e) { /* pass */ } - } - - @Test - public void testRegisterAdapterStateCallbacks() throws Exception { - final IUwbAdapterStateCallbacks cb = mock(IUwbAdapterStateCallbacks.class); - mUwbServiceImpl.registerAdapterStateCallbacks(cb); - - verify(mVendorService).registerAdapterStateCallbacks(cb); - } - - @Test - public void testUnregisterAdapterStateCallbacks() throws Exception { - final IUwbAdapterStateCallbacks cb = mock(IUwbAdapterStateCallbacks.class); - mUwbServiceImpl.unregisterAdapterStateCallbacks(cb); - - verify(mVendorService).unregisterAdapterStateCallbacks(cb); - } - - @Test - public void testGetTimestampResolutionNanos() throws Exception { - final long timestamp = 34L; - when(mVendorService.getTimestampResolutionNanos()).thenReturn(timestamp); - assertThat(mUwbServiceImpl.getTimestampResolutionNanos()).isEqualTo(timestamp); - - verify(mVendorService).getTimestampResolutionNanos(); - } - - @Test - public void testGetSpecificationInfo() throws Exception { - final PersistableBundle specification = new PersistableBundle(); - when(mVendorService.getSpecificationInfo()).thenReturn(specification); - assertThat(mUwbServiceImpl.getSpecificationInfo()).isEqualTo(specification); - - verify(mVendorService).getSpecificationInfo(); - } - - @Test - public void testOpenRanging() throws Exception { - final SessionHandle sessionHandle = new SessionHandle(5); - final IUwbRangingCallbacks cb = mock(IUwbRangingCallbacks.class); - final PersistableBundle parameters = new PersistableBundle(); - final IBinder cbBinder = mock(IBinder.class); - when(cb.asBinder()).thenReturn(cbBinder); - - mUwbServiceImpl.openRanging(ATTRIBUTION_SOURCE, sessionHandle, cb, parameters); - - verify(mVendorService).openRanging( - eq(ATTRIBUTION_SOURCE), eq(sessionHandle), mRangingCbCaptor.capture(), - eq(parameters)); - assertThat(mRangingCbCaptor.getValue()).isNotNull(); - } - - @Test - public void testStartRanging() throws Exception { - final SessionHandle sessionHandle = new SessionHandle(5); - final PersistableBundle parameters = new PersistableBundle(); - - mUwbServiceImpl.startRanging(sessionHandle, parameters); - - verify(mVendorService).startRanging(sessionHandle, parameters); - } - - @Test - public void testReconfigureRanging() throws Exception { - final SessionHandle sessionHandle = new SessionHandle(5); - final PersistableBundle parameters = new PersistableBundle(); - - mUwbServiceImpl.reconfigureRanging(sessionHandle, parameters); - - verify(mVendorService).reconfigureRanging(sessionHandle, parameters); - } - - @Test - public void testStopRanging() throws Exception { - final SessionHandle sessionHandle = new SessionHandle(5); - - mUwbServiceImpl.stopRanging(sessionHandle); - - verify(mVendorService).stopRanging(sessionHandle); - } - - @Test - public void testCloseRanging() throws Exception { - final SessionHandle sessionHandle = new SessionHandle(5); - - mUwbServiceImpl.closeRanging(sessionHandle); - - verify(mVendorService).closeRanging(sessionHandle); - } - - @Test - public void testRangingCallbacks() throws Exception { - final SessionHandle sessionHandle = new SessionHandle(5); - final IUwbRangingCallbacks cb = mock(IUwbRangingCallbacks.class); - final PersistableBundle parameters = new PersistableBundle(); - final IBinder cbBinder = mock(IBinder.class); - when(cb.asBinder()).thenReturn(cbBinder); - - mUwbServiceImpl.openRanging(ATTRIBUTION_SOURCE, sessionHandle, cb, parameters); - - verify(mVendorService).openRanging( - eq(ATTRIBUTION_SOURCE), eq(sessionHandle), mRangingCbCaptor.capture(), - eq(parameters)); - assertThat(mRangingCbCaptor.getValue()).isNotNull(); - - // Invoke vendor service callbacks and ensure that the corresponding app callback is - // invoked. - mRangingCbCaptor.getValue().onRangingOpened(sessionHandle); - verify(cb).onRangingOpened(sessionHandle); - - mRangingCbCaptor.getValue().onRangingOpenFailed( - sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters); - verify(cb).onRangingOpenFailed( - sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters); - - mRangingCbCaptor.getValue().onRangingStarted(sessionHandle, parameters); - verify(cb).onRangingStarted(sessionHandle, parameters); - - mRangingCbCaptor.getValue().onRangingStartFailed( - sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters); - verify(cb).onRangingStartFailed( - sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters); - - mRangingCbCaptor.getValue().onRangingReconfigured(sessionHandle, parameters); - verify(cb).onRangingReconfigured(sessionHandle, parameters); - - mRangingCbCaptor.getValue().onRangingReconfigureFailed( - sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters); - verify(cb).onRangingReconfigureFailed( - sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters); - - mRangingCbCaptor.getValue().onRangingStopped( - sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters); - verify(cb).onRangingStopped( - sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters); - - mRangingCbCaptor.getValue().onRangingStopFailed( - sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters); - verify(cb).onRangingStopFailed( - sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters); - - final RangingReport rangingReport = new RangingReport.Builder().build(); - mRangingCbCaptor.getValue().onRangingResult(sessionHandle, rangingReport); - verify(cb).onRangingResult(sessionHandle, rangingReport); - - mRangingCbCaptor.getValue().onRangingClosed( - sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters); - verify(cb).onRangingClosed( - sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters); - } - - @Test - public void testHandleClientDeath() throws Exception { - final SessionHandle sessionHandle = new SessionHandle(5); - final IUwbRangingCallbacks cb = mock(IUwbRangingCallbacks.class); - final PersistableBundle parameters = new PersistableBundle(); - final IBinder cbBinder = mock(IBinder.class); - when(cb.asBinder()).thenReturn(cbBinder); - - mUwbServiceImpl.openRanging(ATTRIBUTION_SOURCE, sessionHandle, cb, parameters); - - verify(mVendorService).openRanging( - eq(ATTRIBUTION_SOURCE), eq(sessionHandle), mRangingCbCaptor.capture(), - eq(parameters)); - assertThat(mRangingCbCaptor.getValue()).isNotNull(); - - verify(cbBinder).linkToDeath(mClientDeathCaptor.capture(), anyInt()); - assertThat(mClientDeathCaptor.getValue()).isNotNull(); - - clearInvocations(cb); - - // Invoke cb, ensure it reaches the client. - mRangingCbCaptor.getValue().onRangingOpened(sessionHandle); - verify(cb).onRangingOpened(sessionHandle); - - // Trigger client death and ensure the session is stopped. - mClientDeathCaptor.getValue().binderDied(); - verify(mVendorService).stopRanging(sessionHandle); - verify(mVendorService).closeRanging(sessionHandle); - - // Invoke cb, it should be ignored. - mRangingCbCaptor.getValue().onRangingStarted(sessionHandle, parameters); - verify(cb, never()).onRangingStarted(any(), any()); - } - - @Test - public void testHandleVendorServiceDeath() throws Exception { - final SessionHandle sessionHandle = new SessionHandle(5); - final IUwbRangingCallbacks cb = mock(IUwbRangingCallbacks.class); - final PersistableBundle parameters = new PersistableBundle(); - final IBinder cbBinder = mock(IBinder.class); - when(cb.asBinder()).thenReturn(cbBinder); - - mUwbServiceImpl.openRanging(ATTRIBUTION_SOURCE, sessionHandle, cb, parameters); - - verify(mVendorServiceBinder).linkToDeath(mVendorServiceDeathCaptor.capture(), anyInt()); - assertThat(mVendorServiceDeathCaptor.getValue()).isNotNull(); - - verify(mVendorService).openRanging( - eq(ATTRIBUTION_SOURCE), eq(sessionHandle), mRangingCbCaptor.capture(), - eq(parameters)); - assertThat(mRangingCbCaptor.getValue()).isNotNull(); - - clearInvocations(cb); - - // Invoke cb, ensure it reaches the client. - mRangingCbCaptor.getValue().onRangingOpened(sessionHandle); - verify(cb).onRangingOpened(sessionHandle); - - // Trigger vendor service death and ensure that the client is informed of session end. - mVendorServiceDeathCaptor.getValue().binderDied(); - verify(cb).onRangingClosed( - eq(sessionHandle), eq(RangingSession.Callback.REASON_UNKNOWN), - argThat((p) -> p.isEmpty())); - } - - @Test - public void testThrowSecurityExceptionWhenCalledWithoutUwbPrivilegedPermission() - throws Exception { - doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission( - eq(UWB_PRIVILEGED), any()); - final IUwbAdapterStateCallbacks cb = mock(IUwbAdapterStateCallbacks.class); - try { - mUwbServiceImpl.registerAdapterStateCallbacks(cb); - fail(); - } catch (SecurityException e) { /* pass */ } - } - - @Test - public void testThrowSecurityExceptionWhenOpenRangingCalledWithoutUwbRangingPermission() - throws Exception { - doThrow(new SecurityException()).when(mUwbInjector).enforceUwbRangingPermissionForPreflight( - any()); - - final SessionHandle sessionHandle = new SessionHandle(5); - final IUwbRangingCallbacks cb = mock(IUwbRangingCallbacks.class); - final PersistableBundle parameters = new PersistableBundle(); - final IBinder cbBinder = mock(IBinder.class); - when(cb.asBinder()).thenReturn(cbBinder); - try { - mUwbServiceImpl.openRanging(ATTRIBUTION_SOURCE, sessionHandle, cb, parameters); - fail(); - } catch (SecurityException e) { /* pass */ } - } - - @Test - public void testOnRangingResultCallbackNotSentWithoutUwbRangingPermission() throws Exception { - final SessionHandle sessionHandle = new SessionHandle(5); - final IUwbRangingCallbacks cb = mock(IUwbRangingCallbacks.class); - final PersistableBundle parameters = new PersistableBundle(); - final IBinder cbBinder = mock(IBinder.class); - when(cb.asBinder()).thenReturn(cbBinder); - - mUwbServiceImpl.openRanging(ATTRIBUTION_SOURCE, sessionHandle, cb, parameters); - - verify(mVendorService).openRanging( - eq(ATTRIBUTION_SOURCE), eq(sessionHandle), mRangingCbCaptor.capture(), - eq(parameters)); - assertThat(mRangingCbCaptor.getValue()).isNotNull(); - - when(mUwbInjector.checkUwbRangingPermissionForDataDelivery(any(), any())).thenReturn(false); - - // Ensure the ranging cb is not delivered to the client. - final RangingReport rangingReport = new RangingReport.Builder().build(); - mRangingCbCaptor.getValue().onRangingResult(sessionHandle, rangingReport); - verify(cb, never()).onRangingResult(sessionHandle, rangingReport); - } -} diff --git a/services/uwb/Android.bp b/services/uwb/Android.bp deleted file mode 100644 index da30d43a45369..0000000000000 --- a/services/uwb/Android.bp +++ /dev/null @@ -1,26 +0,0 @@ -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "frameworks_base_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["frameworks_base_license"], -} - -filegroup { - name: "services.uwb-sources", - srcs: ["java/**/*.java"], - path: "java", - visibility: ["//frameworks/base/services"], -} - -java_library_static { - name: "services.uwb", - defaults: ["platform_service_defaults"], - srcs: [ - ":services.uwb-sources", - ], - libs: [ - "services.core", - ], -} diff --git a/services/uwb/OWNERS b/services/uwb/OWNERS deleted file mode 100644 index c31a2f1ed3bc5..0000000000000 --- a/services/uwb/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include platform/frameworks/base:/core/java/android/uwb/OWNERS diff --git a/services/uwb/java/com/android/server/uwb/UwbInjector.java b/services/uwb/java/com/android/server/uwb/UwbInjector.java deleted file mode 100644 index 64f1da1c8e16a..0000000000000 --- a/services/uwb/java/com/android/server/uwb/UwbInjector.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2021 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.uwb; - -import static android.Manifest.permission.UWB_RANGING; -import static android.content.PermissionChecker.PERMISSION_GRANTED; - -import android.annotation.NonNull; -import android.content.AttributionSource; -import android.content.Context; -import android.content.PermissionChecker; -import android.os.IBinder; -import android.os.ServiceManager; -import android.uwb.IUwbAdapter; - - -/** - * To be used for dependency injection (especially helps mocking static dependencies). - */ -public class UwbInjector { - private static final String TAG = "UwbInjector"; - - private static final String VENDOR_SERVICE_NAME = "uwb_vendor"; - - private final Context mContext; - - public UwbInjector(@NonNull Context context) { - mContext = context; - } - - /** - * @return Returns the vendor service handle. - */ - public IUwbAdapter getVendorService() { - IBinder b = ServiceManager.getService(VENDOR_SERVICE_NAME); - if (b == null) return null; - return IUwbAdapter.Stub.asInterface(b); - } - - /** - * Throws security exception if the UWB_RANGING permission is not granted for the calling app. - * - *

Should be used in situations where the app op should not be noted. - */ - public void enforceUwbRangingPermissionForPreflight( - @NonNull AttributionSource attributionSource) { - if (!attributionSource.checkCallingUid()) { - throw new SecurityException("Invalid attribution source " + attributionSource); - } - int permissionCheckResult = PermissionChecker.checkPermissionForPreflight( - mContext, UWB_RANGING, attributionSource); - if (permissionCheckResult != PERMISSION_GRANTED) { - throw new SecurityException("Caller does not hold UWB_RANGING permission"); - } - } - - /** - * Returns true if the UWB_RANGING permission is granted for the calling app. - * - *

Should be used in situations where data will be delivered and hence the app op should - * be noted. - */ - public boolean checkUwbRangingPermissionForDataDelivery( - @NonNull AttributionSource attributionSource, @NonNull String message) { - int permissionCheckResult = PermissionChecker.checkPermissionForDataDelivery( - mContext, UWB_RANGING, -1, attributionSource, message); - return permissionCheckResult == PERMISSION_GRANTED; - } -} diff --git a/services/uwb/java/com/android/server/uwb/UwbService.java b/services/uwb/java/com/android/server/uwb/UwbService.java deleted file mode 100644 index 4bb280f75ed12..0000000000000 --- a/services/uwb/java/com/android/server/uwb/UwbService.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2021 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.uwb; - -import android.content.Context; -import android.util.Log; - -import com.android.server.SystemService; - -/** - * Uwb System service. - */ -public class UwbService extends SystemService { - private static final String TAG = "UwbService"; - - private final UwbServiceImpl mImpl; - - public UwbService(Context context) { - super(context); - mImpl = new UwbServiceImpl(context, new UwbInjector(context)); - } - - @Override - public void onStart() { - Log.i(TAG, "Registering " + Context.UWB_SERVICE); - publishBinderService(Context.UWB_SERVICE, mImpl); - } -} diff --git a/services/uwb/java/com/android/server/uwb/UwbServiceImpl.java b/services/uwb/java/com/android/server/uwb/UwbServiceImpl.java deleted file mode 100644 index 4dd26a66cf0ef..0000000000000 --- a/services/uwb/java/com/android/server/uwb/UwbServiceImpl.java +++ /dev/null @@ -1,325 +0,0 @@ -/* - * Copyright (C) 2021 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.uwb; - -import android.annotation.NonNull; -import android.content.AttributionSource; -import android.content.Context; -import android.os.Binder; -import android.os.IBinder; -import android.os.PersistableBundle; -import android.os.RemoteException; -import android.util.ArrayMap; -import android.util.Log; -import android.uwb.IUwbAdapter; -import android.uwb.IUwbAdapterStateCallbacks; -import android.uwb.IUwbRangingCallbacks; -import android.uwb.RangingReport; -import android.uwb.RangingSession; -import android.uwb.SessionHandle; - -import com.android.internal.annotations.GuardedBy; - -import java.util.Map; - -/** - * Implementation of {@link android.uwb.IUwbAdapter} binder service. - */ -public class UwbServiceImpl extends IUwbAdapter.Stub implements IBinder.DeathRecipient{ - private static final String TAG = "UwbServiceImpl"; - - private final Context mContext; - private final UwbInjector mUwbInjector; - /** - * Map for storing the callbacks wrapper for each session. - */ - @GuardedBy("mCallbacksMap") - private final Map mCallbacksMap = new ArrayMap<>(); - - /** - * Used for caching the vendor implementation of {@link IUwbAdapter} interface. - */ - private IUwbAdapter mVendorUwbAdapter; - - /** - * Wrapper for callback registered with vendor service. This wrapper is needed for performing - * permission check before sending the callback to the external app. - * - * Access to these callbacks are synchronized. - */ - private class UwbRangingCallbacksWrapper extends IUwbRangingCallbacks.Stub - implements IBinder.DeathRecipient { - private final AttributionSource mAttributionSource; - private final SessionHandle mSessionHandle; - private final IUwbRangingCallbacks mExternalCb; - private boolean mIsValid; - - UwbRangingCallbacksWrapper(@NonNull AttributionSource attributionSource, - @NonNull SessionHandle sessionHandle, - @NonNull IUwbRangingCallbacks externalCb) { - mAttributionSource = attributionSource; - mSessionHandle = sessionHandle; - mExternalCb = externalCb; - mIsValid = true; - - // Link to death for external callback. - linkToDeath(); - } - - private void linkToDeath() { - IBinder binder = mExternalCb.asBinder(); - try { - binder.linkToDeath(this, 0); - } catch (RemoteException e) { - Log.e(TAG, "Unable to link to client death event.", e); - } - } - - private void removeClientAndUnlinkToDeath() { - // Remove from the map. - synchronized (mCallbacksMap) { - mCallbacksMap.remove(mSessionHandle); - } - IBinder binder = mExternalCb.asBinder(); - binder.unlinkToDeath(this, 0); - mIsValid = false; - } - - - @Override - public synchronized void onRangingOpened(SessionHandle sessionHandle) - throws RemoteException { - if (!mIsValid) return; - mExternalCb.onRangingOpened(sessionHandle); - } - - @Override - public synchronized void onRangingOpenFailed(SessionHandle sessionHandle, - int reason, PersistableBundle parameters) throws RemoteException { - if (!mIsValid) return; - mExternalCb.onRangingOpenFailed(sessionHandle, reason, parameters); - } - - @Override - public synchronized void onRangingStarted(SessionHandle sessionHandle, - PersistableBundle parameters) - throws RemoteException { - if (!mIsValid) return; - mExternalCb.onRangingStarted(sessionHandle, parameters); - } - - @Override - public synchronized void onRangingStartFailed(SessionHandle sessionHandle, - int reason, PersistableBundle parameters) throws RemoteException { - if (!mIsValid) return; - mExternalCb.onRangingStartFailed(sessionHandle, reason, parameters); - } - - @Override - public synchronized void onRangingReconfigured(SessionHandle sessionHandle, - PersistableBundle parameters) - throws RemoteException { - if (!mIsValid) return; - mExternalCb.onRangingReconfigured(sessionHandle, parameters); - } - - @Override - public synchronized void onRangingReconfigureFailed(SessionHandle sessionHandle, - int reason, PersistableBundle parameters) throws RemoteException { - if (!mIsValid) return; - mExternalCb.onRangingReconfigureFailed(sessionHandle, reason, parameters); - } - - @Override - public synchronized void onRangingStopped(SessionHandle sessionHandle, int reason, - PersistableBundle parameters) - throws RemoteException { - if (!mIsValid) return; - mExternalCb.onRangingStopped(sessionHandle, reason, parameters); - } - - @Override - public synchronized void onRangingStopFailed(SessionHandle sessionHandle, int reason, - PersistableBundle parameters) throws RemoteException { - if (!mIsValid) return; - mExternalCb.onRangingStopFailed(sessionHandle, reason, parameters); - } - - @Override - public synchronized void onRangingClosed(SessionHandle sessionHandle, int reason, - PersistableBundle parameters) throws RemoteException { - if (!mIsValid) return; - mExternalCb.onRangingClosed(sessionHandle, reason, parameters); - removeClientAndUnlinkToDeath(); - } - - @Override - public synchronized void onRangingResult(SessionHandle sessionHandle, - RangingReport rangingReport) - throws RemoteException { - if (!mIsValid) return; - boolean permissionGranted = Binder.withCleanCallingIdentity( - () -> mUwbInjector.checkUwbRangingPermissionForDataDelivery( - mAttributionSource, "uwb ranging result")); - if (!permissionGranted) { - Log.e(TAG, "Not delivering ranging result because of permission denial" - + mSessionHandle); - return; - } - mExternalCb.onRangingResult(sessionHandle, rangingReport); - } - - @Override - public synchronized void binderDied() { - if (!mIsValid) return; - Log.i(TAG, "Client died: ending session: " + mSessionHandle); - try { - removeClientAndUnlinkToDeath(); - stopRanging(mSessionHandle); - closeRanging(mSessionHandle); - } catch (RemoteException e) { - Log.e(TAG, "Remote exception while handling client death", e); - } - } - } - - private void linkToVendorServiceDeath() { - IBinder binder = mVendorUwbAdapter.asBinder(); - try { - binder.linkToDeath(this, 0); - } catch (RemoteException e) { - Log.e(TAG, "Unable to link to vendor service death event.", e); - } - } - - @Override - public void binderDied() { - Log.i(TAG, "Vendor service died: sending session close callbacks"); - synchronized (mCallbacksMap) { - for (Map.Entry e : mCallbacksMap.entrySet()) { - try { - e.getValue().mExternalCb.onRangingClosed( - e.getKey(), RangingSession.Callback.REASON_UNKNOWN, - new PersistableBundle()); - } catch (RemoteException ex) { - Log.e(TAG, "Failed to send session close callback " + e.getKey(), ex); - } - } - // Clear all sessions. - mCallbacksMap.clear(); - } - mVendorUwbAdapter = null; - } - - private synchronized IUwbAdapter getVendorUwbAdapter() throws IllegalStateException { - if (mVendorUwbAdapter != null) return mVendorUwbAdapter; - mVendorUwbAdapter = mUwbInjector.getVendorService(); - if (mVendorUwbAdapter == null) { - throw new IllegalStateException("No vendor service found!"); - } - Log.i(TAG, "Retrieved vendor service"); - linkToVendorServiceDeath(); - return mVendorUwbAdapter; - } - - UwbServiceImpl(@NonNull Context context, @NonNull UwbInjector uwbInjector) { - mContext = context; - mUwbInjector = uwbInjector; - } - - private void enforceUwbPrivilegedPermission() { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.UWB_PRIVILEGED, - "UwbService"); - } - - @Override - public void registerAdapterStateCallbacks(IUwbAdapterStateCallbacks adapterStateCallbacks) - throws RemoteException { - enforceUwbPrivilegedPermission(); - getVendorUwbAdapter().registerAdapterStateCallbacks(adapterStateCallbacks); - } - - @Override - public void unregisterAdapterStateCallbacks(IUwbAdapterStateCallbacks adapterStateCallbacks) - throws RemoteException { - enforceUwbPrivilegedPermission(); - getVendorUwbAdapter().unregisterAdapterStateCallbacks(adapterStateCallbacks); - } - - @Override - public long getTimestampResolutionNanos() throws RemoteException { - enforceUwbPrivilegedPermission(); - return getVendorUwbAdapter().getTimestampResolutionNanos(); - } - - @Override - public PersistableBundle getSpecificationInfo() throws RemoteException { - enforceUwbPrivilegedPermission(); - return getVendorUwbAdapter().getSpecificationInfo(); - } - - @Override - public void openRanging(AttributionSource attributionSource, - SessionHandle sessionHandle, IUwbRangingCallbacks rangingCallbacks, - PersistableBundle parameters) throws RemoteException { - enforceUwbPrivilegedPermission(); - mUwbInjector.enforceUwbRangingPermissionForPreflight(attributionSource); - - UwbRangingCallbacksWrapper wrapperCb = - new UwbRangingCallbacksWrapper(attributionSource, sessionHandle, rangingCallbacks); - synchronized (mCallbacksMap) { - mCallbacksMap.put(sessionHandle, wrapperCb); - } - getVendorUwbAdapter().openRanging(attributionSource, sessionHandle, wrapperCb, parameters); - } - - @Override - public void startRanging(SessionHandle sessionHandle, PersistableBundle parameters) - throws RemoteException { - enforceUwbPrivilegedPermission(); - getVendorUwbAdapter().startRanging(sessionHandle, parameters); - } - - @Override - public void reconfigureRanging(SessionHandle sessionHandle, PersistableBundle parameters) - throws RemoteException { - enforceUwbPrivilegedPermission(); - getVendorUwbAdapter().reconfigureRanging(sessionHandle, parameters); - } - - @Override - public void stopRanging(SessionHandle sessionHandle) throws RemoteException { - enforceUwbPrivilegedPermission(); - getVendorUwbAdapter().stopRanging(sessionHandle); - } - - @Override - public void closeRanging(SessionHandle sessionHandle) throws RemoteException { - enforceUwbPrivilegedPermission(); - getVendorUwbAdapter().closeRanging(sessionHandle); - } - - @Override - public synchronized int getAdapterState() throws RemoteException { - return getVendorUwbAdapter().getAdapterState(); - } - - @Override - public synchronized void setEnabled(boolean enabled) throws RemoteException { - getVendorUwbAdapter().setEnabled(enabled); - } -}