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

Commit e001106e authored by Oleg Blinnikov's avatar Oleg Blinnikov Committed by Android (Google) Code Review
Browse files

Merge "Fake WifiDisplay address without location permission" into main

parents f7cd2ee8 54f2ee9a
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import java.util.Objects;
 * @hide
 */
public final class WifiDisplay implements Parcelable {
    private static final String UNKNOWN_MAC_ADDRESS = "00:00:00:00:00:00";
    private final String mDeviceAddress;
    private final String mDeviceName;
    private final String mDeviceAlias;
@@ -193,4 +194,9 @@ public final class WifiDisplay implements Parcelable {
                + ", isRemembered " + mIsRemembered;
        return result;
    }

    public WifiDisplay copy(boolean isDeviceAddressVisible) {
        return new WifiDisplay(isDeviceAddressVisible ? mDeviceAddress : UNKNOWN_MAC_ADDRESS,
                mDeviceName, mDeviceAlias, mIsAvailable, mCanConnect, mIsRemembered);
    }
}
+13 −4
Original line number Diff line number Diff line
@@ -1697,10 +1697,11 @@ public final class DisplayManagerService extends SystemService {
        }
    }

    private WifiDisplayStatus getWifiDisplayStatusInternal() {
    private WifiDisplayStatus getWifiDisplayStatusInternal(boolean hasLocationPermission) {
        synchronized (mSyncRoot) {
            if (mWifiDisplayAdapter != null) {
                return mWifiDisplayAdapter.getWifiDisplayStatusLocked();
                // Device address is visible if the caller has location permission.
                return mWifiDisplayAdapter.getWifiDisplayStatusLocked(hasLocationPermission);
            }
            return new WifiDisplayStatus();
        }
@@ -4156,6 +4157,12 @@ public final class DisplayManagerService extends SystemService {
        }
    }

    @VisibleForTesting
    @Nullable
    WifiDisplayController.Listener getWifiDisplayListener() {
        return mWifiDisplayAdapter != null ? mWifiDisplayAdapter.getWifiDisplayListener() : null;
    }

    private void initializeDisplayPowerControllersLocked() {
        mLogicalDisplayMapper.forEachLocked(this::addDisplayPowerControllerLocked);
    }
@@ -5040,10 +5047,12 @@ public final class DisplayManagerService extends SystemService {
        public WifiDisplayStatus getWifiDisplayStatus() {
            // This request does not require special permissions.
            // Any app can get information about available wifi displays.

            // Except for location permission, which is required to get the wifi display address.
            final boolean hasLocationPermission = checkCallingPermission(
                    android.Manifest.permission.ACCESS_FINE_LOCATION, "getWifiDisplayStatus()");
            final long token = Binder.clearCallingIdentity();
            try {
                return getWifiDisplayStatusInternal();
                return getWifiDisplayStatusInternal(hasLocationPermission);
            } finally {
                Binder.restoreCallingIdentity(token);
            }
+21 −3
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ import android.view.DisplayShape;
import android.view.Surface;
import android.view.SurfaceControl;

import androidx.annotation.VisibleForTesting;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.display.feature.DisplayManagerFlags;
@@ -120,7 +121,8 @@ final class WifiDisplayAdapter extends DisplayAdapter {
    public void dumpLocked(PrintWriter pw) {
        super.dumpLocked(pw);

        pw.println("mCurrentStatus=" + getWifiDisplayStatusLocked());
        pw.println("mCurrentStatus=" + getWifiDisplayStatusLocked(
                /* isDeviceAddressVisible= */ true));
        pw.println("mFeatureState=" + mFeatureState);
        pw.println("mScanState=" + mScanState);
        pw.println("mActiveDisplayState=" + mActiveDisplayState);
@@ -295,7 +297,18 @@ final class WifiDisplayAdapter extends DisplayAdapter {
        }
    }

    public WifiDisplayStatus getWifiDisplayStatusLocked() {
    public WifiDisplayStatus getWifiDisplayStatusLocked(boolean isDeviceAddressVisible) {
        if (!isDeviceAddressVisible) {
            var displaysCopy = new WifiDisplay[mDisplays.length];
            for (int i = 0; i < mDisplays.length; i++) {
                displaysCopy[i] = mDisplays[i].copy(isDeviceAddressVisible);
            }
            var activeDisplayCopy =
                mActiveDisplay == null ? null : mActiveDisplay.copy(isDeviceAddressVisible);
            return new WifiDisplayStatus(mFeatureState, mScanState, mActiveDisplayState,
                    activeDisplayCopy, displaysCopy, mSessionInfo);
        }

        if (mCurrentStatus == null) {
            mCurrentStatus = new WifiDisplayStatus(
                    mFeatureState, mScanState, mActiveDisplayState,
@@ -308,6 +321,11 @@ final class WifiDisplayAdapter extends DisplayAdapter {
        return mCurrentStatus;
    }

    @VisibleForTesting
    public WifiDisplayController.Listener getWifiDisplayListener() {
        return mWifiDisplayListener;
    }

    private void updateDisplaysLocked() {
        List<WifiDisplay> displays = new ArrayList<WifiDisplay>(
                mAvailableDisplays.length + mRememberedDisplays.length);
@@ -438,7 +456,7 @@ final class WifiDisplayAdapter extends DisplayAdapter {
            intent = new Intent(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED);
            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
            intent.putExtra(DisplayManager.EXTRA_WIFI_DISPLAY_STATUS,
                    getWifiDisplayStatusLocked());
                    getWifiDisplayStatusLocked(/* isDeviceAddressVisible= */ true));

            options = BroadcastOptions.makeBasic();
            options.setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT);
+73 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.display;

import static android.Manifest.permission.ACCESS_FINE_LOCATION;
import static android.Manifest.permission.ADD_ALWAYS_UNLOCKED_DISPLAY;
import static android.Manifest.permission.ADD_TRUSTED_DISPLAY;
import static android.Manifest.permission.CAPTURE_VIDEO_OUTPUT;
@@ -126,8 +127,10 @@ import android.hardware.display.HdrConversionMode;
import android.hardware.display.IDisplayManagerCallback;
import android.hardware.display.IVirtualDisplayCallback;
import android.hardware.display.VirtualDisplayConfig;
import android.hardware.display.WifiDisplay;
import android.media.projection.IMediaProjection;
import android.media.projection.IMediaProjectionManager;
import android.net.wifi.p2p.WifiP2pManager;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
@@ -232,6 +235,7 @@ import java.util.stream.LongStream;
@RunWith(JUnitParamsRunner.class)
public class DisplayManagerServiceTest {
    private static final int MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS = 1;
    private static final int MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS = 2;
    private static final long SHORT_DEFAULT_DISPLAY_TIMEOUT_MILLIS = 10;

    private static final float FLOAT_TOLERANCE = 0.01f;
@@ -446,6 +450,7 @@ public class DisplayManagerServiceTest {
    @Mock WindowManagerPolicy mMockedWindowManagerPolicy;

    @Mock IBatteryStats mMockedBatteryStats;
    @Mock WifiP2pManager mMockedWifiP2pManager;

    @Rule
    public final ExtendedMockitoRule mExtendedMockitoRule =
@@ -4274,6 +4279,66 @@ public class DisplayManagerServiceTest {
        assertThrows(SecurityException.class, displayManagerBinderService::resumeWifiDisplay);
    }

    @Test
    public void getWifiDisplayStatus_withoutFineLocationPermission_shouldReturnFakeAddress() {
        doNothing().when(mContext).sendBroadcastAsUser(any(), any(), isNull(), any());
        doReturn(mMockedWifiP2pManager).when(mContext).getSystemService(Context.WIFI_P2P_SERVICE);
        doReturn(true).when(mResources).getBoolean(R.bool.config_enableWifiDisplay);
        DisplayManagerService displayManager =
                new DisplayManagerService(mContext, mBasicInjector);
        DisplayManagerService.BinderService displayManagerBinderService =
                displayManager.new BinderService();
        registerDefaultDisplays(displayManager);
        displayManager.systemReady(/* safeMode= */ false);
        registerAdditionalDisplays(displayManager);

        var wifiDisplayListener = displayManager.getWifiDisplayListener();

        WifiDisplay[] availableDisplays = new WifiDisplay[1];
        availableDisplays[0] = new WifiDisplay(
                /* deviceAddress = */ "11:22:33:44:55:66",
                /* deviceName= */ "deviceName",
                /* deviceAlias= */ "deviceAlias",
                /* available= */ true,
                /* canConnect= */ true,
                /* remembered= */ false);
        wifiDisplayListener.onScanResults(availableDisplays);

        assertThat(displayManagerBinderService.getWifiDisplayStatus().getDisplays()[0]
                       .getDeviceAddress()).isEqualTo("00:00:00:00:00:00");
    }

    @Test
    public void getWifiDisplayStatus_withFineLocationPermission_shouldReturnRealAddress() {
        doNothing().when(mContext).sendBroadcastAsUser(any(), any(), isNull(), any());
        doReturn(mMockedWifiP2pManager).when(mContext).getSystemService(Context.WIFI_P2P_SERVICE);
        doReturn(true).when(mResources).getBoolean(R.bool.config_enableWifiDisplay);
        when(mContext.checkCallingPermission(ACCESS_FINE_LOCATION)).thenReturn(
                PackageManager.PERMISSION_GRANTED);
        DisplayManagerService displayManager =
                new DisplayManagerService(mContext, mBasicInjector);
        DisplayManagerService.BinderService displayManagerBinderService =
                displayManager.new BinderService();
        registerDefaultDisplays(displayManager);
        displayManager.systemReady(/* safeMode= */ false);
        registerAdditionalDisplays(displayManager);

        var wifiDisplayListener = displayManager.getWifiDisplayListener();

        WifiDisplay[] availableDisplays = new WifiDisplay[1];
        availableDisplays[0] = new WifiDisplay(
                /* deviceAddress = */ "11:22:33:44:55:66",
                /* deviceName= */ "deviceName",
                /* deviceAlias= */ "deviceAlias",
                /* available= */ true,
                /* canConnect= */ true,
                /* remembered= */ false);
        wifiDisplayListener.onScanResults(availableDisplays);

        assertThat(displayManagerBinderService.getWifiDisplayStatus().getDisplays()[0]
                       .getDeviceAddress()).isEqualTo("11:22:33:44:55:66");
    }

    @Test
    public void setUserDisabledHdrTypes_withoutPermission_shouldThrowException() {
        DisplayManagerService displayManager =
@@ -5046,6 +5111,14 @@ public class DisplayManagerServiceTest {
        flushHandlers();
    }

    private void registerAdditionalDisplays(DisplayManagerService displayManager) {
        Handler handler = displayManager.getDisplayHandler();
        // Would prefer to call displayManager.onStart() directly here but it performs binderService
        // registration which triggers security exceptions when running from a test.
        handler.sendEmptyMessage(MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS);
        flushHandlers();
    }

    private void flushHandlers() {
        com.android.server.testutils.TestUtils.flushLoopers(mDisplayLooperManager,
                mPowerLooperManager, mBackgroundLooperManager);