Merge changes from topic "uwb_aosp_service" into sc-dev

* changes:
  UwbService: Handle vendor service death
  UwbService: Create a UwbRanging callback wrapper
  Uwb: Create a new Uwb system service
This commit is contained in:
Roshan Pius
2021-04-14 03:26:40 +00:00
committed by Android (Google) Code Review
9 changed files with 714 additions and 3 deletions

View File

@@ -24,9 +24,7 @@ import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.content.AttributionSource;
import android.content.Context;
import android.content.ContextParams;
import android.os.CancellationSignal;
import android.os.IBinder;
import android.os.PersistableBundle;
@@ -49,7 +47,7 @@ import java.util.concurrent.Executor;
@SystemApi
@SystemService(Context.UWB_SERVICE)
public final class UwbManager {
private static final String SERVICE_NAME = "uwb";
private static final String SERVICE_NAME = Context.UWB_SERVICE;
private final Context mContext;
private final IUwbAdapter mUwbAdapter;

View File

@@ -65,6 +65,7 @@ filegroup {
":services.texttospeech-sources",
":services.usage-sources",
":services.usb-sources",
":services.uwb-sources",
":services.voiceinteraction-sources",
":services.wifi-sources",
],
@@ -129,6 +130,7 @@ java_library {
"services.texttospeech",
"services.usage",
"services.usb",
"services.uwb",
"services.voiceinteraction",
"services.wifi",
"service-blobstore",

View File

@@ -384,6 +384,7 @@ 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_SERVICE_CLASS = "com.android.server.uwb.UwbService";
private static final String TETHERING_CONNECTOR_CLASS = "android.net.ITetheringConnector";
@@ -2637,6 +2638,12 @@ public final class SystemServer implements Dumpable {
LocalManagerRegistry.addManager(ArtManagerLocal.class, new ArtManagerLocal());
t.traceEnd();
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_UWB)) {
t.traceBegin("UwbService");
mSystemServiceManager.startService(UWB_SERVICE_CLASS);
t.traceEnd();
}
t.traceBegin("StartBootPhaseDeviceSpecificServicesReady");
mSystemServiceManager.startBootPhase(t, SystemService.PHASE_DEVICE_SPECIFIC_SERVICES_READY);
t.traceEnd();

View File

@@ -37,6 +37,7 @@ android_test {
"services.net",
"services.people",
"services.usage",
"services.uwb",
"guava",
"androidx.test.core",
"androidx.test.ext.truth",

View File

@@ -0,0 +1,299 @@
/*
* 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 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.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
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 {
@Mock private IUwbAdapter mVendorService;
@Mock private IBinder mVendorServiceBinder;
@Mock private Context mContext;
@Mock private UwbInjector mUwbInjector;
@Captor private ArgumentCaptor<IUwbRangingCallbacks> mRangingCbCaptor;
@Captor private ArgumentCaptor<IBinder.DeathRecipient> mClientDeathCaptor;
@Captor private ArgumentCaptor<IBinder.DeathRecipient> mVendorServiceDeathCaptor;
private UwbServiceImpl mUwbServiceImpl;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
when(mUwbInjector.getVendorService()).thenReturn(mVendorService);
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(sessionHandle, cb, parameters);
verify(mVendorService).openRanging(
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(sessionHandle, cb, parameters);
verify(mVendorService).openRanging(
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(sessionHandle, cb, parameters);
verify(mVendorService).openRanging(
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(sessionHandle, cb, parameters);
verify(mVendorServiceBinder).linkToDeath(mVendorServiceDeathCaptor.capture(), anyInt());
assertThat(mVendorServiceDeathCaptor.getValue()).isNotNull();
verify(mVendorService).openRanging(
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()));
}
}

26
services/uwb/Android.bp Normal file
View File

@@ -0,0 +1,26 @@
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",
],
}

View File

@@ -0,0 +1,48 @@
/*
* 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.Context;
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);
}
}

View File

@@ -0,0 +1,42 @@
/*
* 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);
}
}

View File

@@ -0,0 +1,288 @@
/*
* 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.Context;
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<SessionHandle, UwbRangingCallbacksWrapper> 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 SessionHandle mSessionHandle;
private final IUwbRangingCallbacks mExternalCb;
private boolean mIsValid;
UwbRangingCallbacksWrapper(@NonNull SessionHandle sessionHandle,
@NonNull IUwbRangingCallbacks externalCb) {
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;
// TODO: Perform permission checks and noteOp.
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<SessionHandle, UwbRangingCallbacksWrapper> 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;
}
@Override
public void registerAdapterStateCallbacks(IUwbAdapterStateCallbacks adapterStateCallbacks)
throws RemoteException {
getVendorUwbAdapter().registerAdapterStateCallbacks(adapterStateCallbacks);
}
@Override
public void unregisterAdapterStateCallbacks(IUwbAdapterStateCallbacks adapterStateCallbacks)
throws RemoteException {
getVendorUwbAdapter().unregisterAdapterStateCallbacks(adapterStateCallbacks);
}
@Override
public long getTimestampResolutionNanos() throws RemoteException {
return getVendorUwbAdapter().getTimestampResolutionNanos();
}
@Override
public PersistableBundle getSpecificationInfo() throws RemoteException {
return getVendorUwbAdapter().getSpecificationInfo();
}
@Override
public void openRanging(SessionHandle sessionHandle, IUwbRangingCallbacks rangingCallbacks,
PersistableBundle parameters) throws RemoteException {
UwbRangingCallbacksWrapper wrapperCb =
new UwbRangingCallbacksWrapper(sessionHandle, rangingCallbacks);
synchronized (mCallbacksMap) {
mCallbacksMap.put(sessionHandle, wrapperCb);
}
getVendorUwbAdapter().openRanging(sessionHandle, wrapperCb, parameters);
}
@Override
public void startRanging(SessionHandle sessionHandle, PersistableBundle parameters)
throws RemoteException {
// TODO: Perform permission checks.
getVendorUwbAdapter().startRanging(sessionHandle, parameters);
}
@Override
public void reconfigureRanging(SessionHandle sessionHandle, PersistableBundle parameters)
throws RemoteException {
getVendorUwbAdapter().reconfigureRanging(sessionHandle, parameters);
}
@Override
public void stopRanging(SessionHandle sessionHandle) throws RemoteException {
getVendorUwbAdapter().stopRanging(sessionHandle);
}
@Override
public void closeRanging(SessionHandle sessionHandle) throws RemoteException {
getVendorUwbAdapter().closeRanging(sessionHandle);
}
}