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

Commit 8ed5af47 authored by George Chan's avatar George Chan
Browse files

Moved UsbManagerInternal to framework core so other System Services outside of...

Moved UsbManagerInternal to framework core so other System Services outside of USB can access it (currently there will only be one caller which is UsbDataAdvancedProtectionHook.)

As the UsbManagerInternal is now moved outside of UsbService space, it has been reshaped to be similar to UsbManager to make it more consistent and avoid excess differentiation between Manager clients.

Currently no service is consuming the client. But will be in a subsequent CL.

Bug: 399146898
Change-Id: Iad36ce274a9c444f7c697503a7a4bd39e9df2986
Test: atest UsbServiceTest, manual test
Flag: android.hardware.usb.flags.enable_usb_data_signal_staking_internal
parent 40b100e3
Loading
Loading
Loading
Loading
+26 −0
Original line number Original line Diff line number Diff line
/*
/*
 * Copyright (C) 2024 The Android Open Source Project
 * Copyright (C) 2025 The Android Open Source Project
 *
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * you may not use this file except in compliance with the License.
@@ -14,37 +14,13 @@
 * limitations under the License.
 * limitations under the License.
 */
 */


package com.android.server.usb;
package android.hardware.usb;


import android.annotation.IntDef;
import android.annotation.NonNull;
import android.hardware.usb.IUsbOperationInternal;
import android.hardware.usb.IUsbOperationInternal;
import android.hardware.usb.UsbPort;
import android.util.ArraySet;


import java.lang.annotation.Retention;
/** @hide */
import java.lang.annotation.RetentionPolicy;
interface IUsbManagerInternal {

/**
 * UsbManagerInternal provides internal APIs for the UsbService to
 * reduce IPC overhead costs and support internal USB data signal stakers.
 *
 * @hide Only for use within the system server.
 */
public abstract class UsbManagerInternal {

  public static final int OS_USB_DISABLE_REASON_AAPM = 0;
  public static final int OS_USB_DISABLE_REASON_LOCKDOWN_MODE = 1;

  @Retention(RetentionPolicy.SOURCE)
  @IntDef(value = {OS_USB_DISABLE_REASON_AAPM,
    OS_USB_DISABLE_REASON_LOCKDOWN_MODE})
  public @interface OsUsbDisableReason {
  }

  public abstract boolean enableUsbData(String portId, boolean enable,
      int operationId, IUsbOperationInternal callback, @OsUsbDisableReason int disableReason);

  public abstract UsbPort[] getPorts();


    /* Disable/enable USB data on a port for System Service callers. */
    boolean enableUsbDataSignal(boolean enable, int disableReason);
}
}
+35 −13
Original line number Original line Diff line number Diff line
@@ -27,7 +27,10 @@ import static android.hardware.usb.UsbPortStatus.MODE_UFP;
import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK;
import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK;
import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE;
import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE;


import android.hardware.usb.IUsbManagerInternal;

import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.IntDef;
import android.annotation.UserIdInt;
import android.annotation.UserIdInt;
import android.app.PendingIntent;
import android.app.PendingIntent;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManager;
@@ -80,12 +83,16 @@ import dalvik.annotation.optimization.NeverCompile;
import java.io.File;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Collections;
import java.util.List;
import java.util.List;
import java.util.Objects;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletableFuture;


import java.util.concurrent.atomic.AtomicInteger;

/**
/**
 * UsbService manages all USB related state, including both host and device support.
 * UsbService manages all USB related state, including both host and device support.
 * Host related events and calls are delegated to UsbHostManager, and device related
 * Host related events and calls are delegated to UsbHostManager, and device related
@@ -93,6 +100,15 @@ import java.util.concurrent.CompletableFuture;
 */
 */
public class UsbService extends IUsbManager.Stub {
public class UsbService extends IUsbManager.Stub {


    public static final int OS_USB_DISABLE_REASON_AAPM = 0;
    public static final int OS_USB_DISABLE_REASON_LOCKDOWN_MODE = 1;

    @Retention(RetentionPolicy.SOURCE)
    @IntDef(value = {OS_USB_DISABLE_REASON_AAPM,
        OS_USB_DISABLE_REASON_LOCKDOWN_MODE})
    public @interface OsUsbDisableReason {
    }

    public static class Lifecycle extends SystemService {
    public static class Lifecycle extends SystemService {
        private UsbService mUsbService;
        private UsbService mUsbService;
        private final CompletableFuture<Void> mOnStartFinished = new CompletableFuture<>();
        private final CompletableFuture<Void> mOnStartFinished = new CompletableFuture<>();
@@ -227,7 +243,7 @@ public class UsbService extends IUsbManager.Stub {
        filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
        filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
        mContext.registerReceiverAsUser(receiver, UserHandle.ALL, filter, null, null);
        mContext.registerReceiverAsUser(receiver, UserHandle.ALL, filter, null, null);
        if(android.hardware.usb.flags.Flags.enableUsbDataSignalStakingInternal()) {
        if(android.hardware.usb.flags.Flags.enableUsbDataSignalStakingInternal()) {
            LocalServices.addService(UsbManagerInternal.class, new UsbManagerInternalImpl());
            LocalServices.addService(IUsbManagerInternal.class, new UsbManagerInternalImpl());
        }
        }
    }
    }


@@ -246,7 +262,7 @@ public class UsbService extends IUsbManager.Stub {
        mPermissionManager = new UsbPermissionManager(context, this);
        mPermissionManager = new UsbPermissionManager(context, this);


        if(android.hardware.usb.flags.Flags.enableUsbDataSignalStakingInternal()) {
        if(android.hardware.usb.flags.Flags.enableUsbDataSignalStakingInternal()) {
            LocalServices.addService(UsbManagerInternal.class, new UsbManagerInternalImpl());
            LocalServices.addService(IUsbManagerInternal.class, new UsbManagerInternalImpl());
        }
        }
    }
    }


@@ -1536,24 +1552,30 @@ public class UsbService extends IUsbManager.Stub {
                enableUsbDataInternal(port.getId(), !lockDownTriggeredByUser,
                enableUsbDataInternal(port.getId(), !lockDownTriggeredByUser,
                    STRONG_AUTH_OPERATION_ID,
                    STRONG_AUTH_OPERATION_ID,
                    new IUsbOperationInternal.Default(),
                    new IUsbOperationInternal.Default(),
                    UsbManagerInternal.OS_USB_DISABLE_REASON_LOCKDOWN_MODE,
                    OS_USB_DISABLE_REASON_LOCKDOWN_MODE,
                    true);
                    true);
            }
            }
        }
        }
    }
    }


    private class UsbManagerInternalImpl extends UsbManagerInternal {
    private class UsbManagerInternalImpl extends IUsbManagerInternal.Stub {
        private static final AtomicInteger sUsbOperationCount = new AtomicInteger();

        @Override
        @Override
        public boolean enableUsbData(String portId, boolean enable,
        public boolean enableUsbDataSignal(boolean enable,
                int operationId, IUsbOperationInternal callback,
                @OsUsbDisableReason int disableReason) {
                @OsUsbDisableReason int disableReason) {
            return enableUsbDataInternal(portId, enable, operationId, callback,
                boolean result = true;
                disableReason, true);
                int operationId = sUsbOperationCount.incrementAndGet() + disableReason;
                for (UsbPort port : mPortManager.getPorts()) {
                    boolean success = enableUsbDataInternal(port.getId(), enable, operationId,
                        new IUsbOperationInternal.Default(), disableReason, true);
                    if(!success) {
                        Slog.e(TAG, "enableUsbDataInternal failed to change USB port "
                            + port.getId() + "state to " + enable);
                    }
                    }

                    result &= success;
        @Override
                }
        public UsbPort[] getPorts() {
                return result;
            return mPortManager.getPorts();
        }
        }
    }
    }
}
}
+43 −24
Original line number Original line Diff line number Diff line
@@ -24,15 +24,20 @@ import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.when;


import android.content.Context;
import android.content.Context;
import android.hardware.usb.IUsbManagerInternal;
import android.hardware.usb.IUsbOperationInternal;
import android.hardware.usb.IUsbOperationInternal;
import android.hardware.usb.flags.Flags;
import android.hardware.usb.flags.Flags;
import android.hardware.usb.UsbPort;
import android.hardware.usb.UsbPort;
@@ -70,7 +75,9 @@ public class UsbServiceTest {
    @Mock
    @Mock
    private IUsbOperationInternal mCallback;
    private IUsbOperationInternal mCallback;


    private static final String TEST_PORT_ID = "123";
    private static final String TEST_PORT_ID = "1";

    private static final String TEST_PORT_ID_2 = "2";


    private static final int TEST_TRANSACTION_ID = 1;
    private static final int TEST_TRANSACTION_ID = 1;


@@ -84,7 +91,7 @@ public class UsbServiceTest {


    private UsbService mUsbService;
    private UsbService mUsbService;


    private UsbManagerInternal mUsbManagerInternal;
    private IUsbManagerInternal mIUsbManagerInternal;


    @Rule
    @Rule
    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@@ -101,9 +108,9 @@ public class UsbServiceTest {


        mUsbService = new UsbService(mContext, mUsbPortManager, mUsbAlsaManager,
        mUsbService = new UsbService(mContext, mUsbPortManager, mUsbAlsaManager,
                mUserManager, mUsbSettingsManager);
                mUserManager, mUsbSettingsManager);
        mUsbManagerInternal = LocalServices.getService(UsbManagerInternal.class);
        mIUsbManagerInternal = LocalServices.getService(IUsbManagerInternal.class);
        assertWithMessage("LocalServices.getService(UsbManagerInternal.class)")
        assertWithMessage("LocalServices.getService(IUsbManagerInternal.class)")
            .that(mUsbManagerInternal).isNotNull();
            .that(mIUsbManagerInternal).isNotNull();
    }
    }


    private void assertToggleUsbSuccessfully(int requester, boolean enable,
    private void assertToggleUsbSuccessfully(int requester, boolean enable,
@@ -255,30 +262,42 @@ public class UsbServiceTest {
        assertToggleUsbSuccessfully(TEST_INTERNAL_REQUESTER_REASON_1, true, false);
        assertToggleUsbSuccessfully(TEST_INTERNAL_REQUESTER_REASON_1, true, false);
    }
    }


    /**
     * Verify USB Manager internal calls mPortManager to get UsbPorts
     */
    @Test
    @Test
    public void usbManagerInternal_getPorts_callsPortManager() {
    public void usbManagerInternal_enableUsbDataSignal_successfullyEnabled() {
        when(mUsbPortManager.getPorts()).thenReturn(new UsbPort[] {});
        assertTrue(runInternalUsbDataSignalTest(true, true, true));

        UsbPort[] ports = mUsbManagerInternal.getPorts();

        verify(mUsbPortManager).getPorts();
        assertEquals(ports.length, 0);
    }
    }


    @Test
    @Test
    public void usbManagerInternal_enableUsbData_successfullyEnable() {
    public void usbManagerInternal_enableUsbDataSignal_successfullyDisabled() {
        boolean desiredEnableState = true;
        assertTrue(runInternalUsbDataSignalTest(false, true, true));
    }


        assertTrue(mUsbManagerInternal.enableUsbData(TEST_PORT_ID, desiredEnableState,
    @Test
        TEST_TRANSACTION_ID, mCallback, TEST_INTERNAL_REQUESTER_REASON_1));
    public void usbManagerInternal_enableUsbDataSignal_returnsFalseIfOnePortFails() {
        assertFalse(runInternalUsbDataSignalTest(true, true, false));
    }


        verify(mUsbPortManager).enableUsbData(TEST_PORT_ID,
    private boolean runInternalUsbDataSignalTest(boolean desiredEnableState, boolean portOneSuccess,
                desiredEnableState, TEST_TRANSACTION_ID, mCallback, null);
        boolean portTwoSuccess) {
        verifyZeroInteractions(mCallback);
        UsbPort port = mock(UsbPort.class);
        UsbPort port2 = mock(UsbPort.class);
        when(port.getId()).thenReturn(TEST_PORT_ID);
        when(port2.getId()).thenReturn(TEST_PORT_ID_2);
        when(mUsbPortManager.getPorts()).thenReturn(new UsbPort[] { port, port2 });
        when(mUsbPortManager.enableUsbData(eq(TEST_PORT_ID),
                eq(desiredEnableState), anyInt(), any(IUsbOperationInternal.class), isNull()))
            .thenReturn(portOneSuccess);
        when(mUsbPortManager.enableUsbData(eq(TEST_PORT_ID_2),
                eq(desiredEnableState), anyInt(), any(IUsbOperationInternal.class), isNull()))
            .thenReturn(portTwoSuccess);
        try {
            boolean result = mIUsbManagerInternal.enableUsbDataSignal(desiredEnableState,
                        TEST_INTERNAL_REQUESTER_REASON_1);
            clearInvocations(mUsbPortManager);
            clearInvocations(mUsbPortManager);
        clearInvocations(mCallback);
            return result;
        } catch(RemoteException e) {
            fail("RemoteException thrown when calling enableUsbDataSignal");
            return false;
        }
    }
    }
}
}