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

Commit ab67bc73 authored by George Chan's avatar George Chan Committed by Android (Google) Code Review
Browse files

Merge "Moved UsbManagerInternal to framework core so other System Services...

Merge "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.)" into main
parents eae8ce83 8ed5af47
Loading
Loading
Loading
Loading
+26 −0
Original line number 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");
 * you may not use this file except in compliance with the License.
@@ -14,37 +14,13 @@
 * 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.UsbPort;
import android.util.ArraySet;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * 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();
/** @hide */
interface IUsbManagerInternal {

    /* Disable/enable USB data on a port for System Service callers. */
    boolean enableUsbDataSignal(boolean enable, int disableReason);
}
+35 −13
Original line number 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_SOURCE;

import android.hardware.usb.IUsbManagerInternal;

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

import java.util.concurrent.atomic.AtomicInteger;

/**
 * UsbService manages all USB related state, including both host and device support.
 * 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 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 {
        private UsbService mUsbService;
        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);
        mContext.registerReceiverAsUser(receiver, UserHandle.ALL, filter, null, null);
        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);

        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,
                    STRONG_AUTH_OPERATION_ID,
                    new IUsbOperationInternal.Default(),
                    UsbManagerInternal.OS_USB_DISABLE_REASON_LOCKDOWN_MODE,
                    OS_USB_DISABLE_REASON_LOCKDOWN_MODE,
                    true);
            }
        }
    }

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

        @Override
        public boolean enableUsbData(String portId, boolean enable,
                int operationId, IUsbOperationInternal callback,
        public boolean enableUsbDataSignal(boolean enable,
                @OsUsbDisableReason int disableReason) {
            return enableUsbDataInternal(portId, enable, operationId, callback,
                disableReason, true);
                boolean result = 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);
                    }

        @Override
        public UsbPort[] getPorts() {
            return mPortManager.getPorts();
                    result &= success;
                }
                return result;
        }
    }
}
+43 −24
Original line number 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.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;

import android.content.Context;
import android.hardware.usb.IUsbManagerInternal;
import android.hardware.usb.IUsbOperationInternal;
import android.hardware.usb.flags.Flags;
import android.hardware.usb.UsbPort;
@@ -70,7 +75,9 @@ public class UsbServiceTest {
    @Mock
    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;

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

    private UsbService mUsbService;

    private UsbManagerInternal mUsbManagerInternal;
    private IUsbManagerInternal mIUsbManagerInternal;

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

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

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

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

        UsbPort[] ports = mUsbManagerInternal.getPorts();

        verify(mUsbPortManager).getPorts();
        assertEquals(ports.length, 0);
    public void usbManagerInternal_enableUsbDataSignal_successfullyEnabled() {
        assertTrue(runInternalUsbDataSignalTest(true, true, true));
    }

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

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

        verify(mUsbPortManager).enableUsbData(TEST_PORT_ID,
                desiredEnableState, TEST_TRANSACTION_ID, mCallback, null);
        verifyZeroInteractions(mCallback);
    private boolean runInternalUsbDataSignalTest(boolean desiredEnableState, boolean portOneSuccess,
        boolean portTwoSuccess) {
        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(mCallback);
            return result;
        } catch(RemoteException e) {
            fail("RemoteException thrown when calling enableUsbDataSignal");
            return false;
        }
    }
}