Uwb: Create a new Uwb system service
This thin AOSP service layer will trampoline all API calls to the vendor UWB service. In follow up CL's, i. The AOSP service will perform all the permission checks necessary for this API surface before forwarding the call to the vendor UWB service. ii. Similarly, it will perform necessary permission checks + noteOp before forwarding the ranging callbacks from the vendor service back to the apps. Bug: 183904955 Test: atest android.uwb.cts.UwbManagerTest Test: atest com.android.server.uwb Change-Id: I2b367d1b6accc2f4e075cacb5c8e3c51f1faf5db
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -37,6 +37,7 @@ android_test {
|
||||
"services.net",
|
||||
"services.people",
|
||||
"services.usage",
|
||||
"services.uwb",
|
||||
"guava",
|
||||
"androidx.test.core",
|
||||
"androidx.test.ext.truth",
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* 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.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
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.SessionHandle;
|
||||
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
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 Context mContext;
|
||||
@Mock private UwbInjector mUwbInjector;
|
||||
|
||||
private UwbServiceImpl mUwbServiceImpl;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
when(mUwbInjector.getVendorService()).thenReturn(mVendorService);
|
||||
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();
|
||||
|
||||
mUwbServiceImpl.openRanging(sessionHandle, cb, parameters);
|
||||
|
||||
verify(mVendorService).openRanging(sessionHandle, cb, parameters);
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
||||
26
services/uwb/Android.bp
Normal file
26
services/uwb/Android.bp
Normal 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",
|
||||
],
|
||||
}
|
||||
48
services/uwb/java/com/android/server/uwb/UwbInjector.java
Normal file
48
services/uwb/java/com/android/server/uwb/UwbInjector.java
Normal 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);
|
||||
}
|
||||
}
|
||||
42
services/uwb/java/com/android/server/uwb/UwbService.java
Normal file
42
services/uwb/java/com/android/server/uwb/UwbService.java
Normal 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);
|
||||
}
|
||||
}
|
||||
107
services/uwb/java/com/android/server/uwb/UwbServiceImpl.java
Normal file
107
services/uwb/java/com/android/server/uwb/UwbServiceImpl.java
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* 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.PersistableBundle;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
import android.uwb.IUwbAdapter;
|
||||
import android.uwb.IUwbAdapterStateCallbacks;
|
||||
import android.uwb.IUwbRangingCallbacks;
|
||||
import android.uwb.SessionHandle;
|
||||
|
||||
/**
|
||||
* Implementation of {@link android.uwb.IUwbAdapter} binder service.
|
||||
*/
|
||||
public class UwbServiceImpl extends IUwbAdapter.Stub {
|
||||
private static final String TAG = "UwbServiceImpl";
|
||||
|
||||
private final Context mContext;
|
||||
private final UwbInjector mUwbInjector;
|
||||
|
||||
/**
|
||||
* Used for caching the vendor implementation of {@link IUwbAdapter} interface.
|
||||
*/
|
||||
private IUwbAdapter mVendorUwbAdapter;
|
||||
|
||||
private 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");
|
||||
return mVendorUwbAdapter;
|
||||
}
|
||||
|
||||
public 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 {
|
||||
getVendorUwbAdapter().openRanging(sessionHandle, rangingCallbacks, parameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startRanging(SessionHandle sessionHandle, PersistableBundle parameters)
|
||||
throws RemoteException {
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user