Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 27e1a87a authored by Roshan Pius's avatar Roshan Pius
Browse files

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
parent 2e139344
Loading
Loading
Loading
Loading
+1 −3
Original line number Diff line number Diff line
@@ -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;
+2 −0
Original line number Diff line number Diff line
@@ -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",
+7 −0
Original line number Diff line number Diff line
@@ -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();
+1 −0
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ android_test {
        "services.net",
        "services.people",
        "services.usage",
        "services.uwb",
        "guava",
        "androidx.test.core",
        "androidx.test.ext.truth",
+156 −0
Original line number Diff line number Diff line
/*
 * 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);
    }
}
Loading