Loading core/java/android/hardware/display/WifiDisplay.java +6 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } } services/core/java/com/android/server/display/DisplayManagerService.java +13 −4 Original line number Diff line number Diff line Loading @@ -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(); } Loading Loading @@ -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); } Loading Loading @@ -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); } Loading services/core/java/com/android/server/display/WifiDisplayAdapter.java +21 −3 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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, Loading @@ -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); Loading Loading @@ -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); Loading services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java +73 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -446,6 +450,7 @@ public class DisplayManagerServiceTest { @Mock WindowManagerPolicy mMockedWindowManagerPolicy; @Mock IBatteryStats mMockedBatteryStats; @Mock WifiP2pManager mMockedWifiP2pManager; @Rule public final ExtendedMockitoRule mExtendedMockitoRule = Loading Loading @@ -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 = Loading Loading @@ -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); Loading Loading
core/java/android/hardware/display/WifiDisplay.java +6 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } }
services/core/java/com/android/server/display/DisplayManagerService.java +13 −4 Original line number Diff line number Diff line Loading @@ -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(); } Loading Loading @@ -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); } Loading Loading @@ -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); } Loading
services/core/java/com/android/server/display/WifiDisplayAdapter.java +21 −3 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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, Loading @@ -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); Loading Loading @@ -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); Loading
services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java +73 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -446,6 +450,7 @@ public class DisplayManagerServiceTest { @Mock WindowManagerPolicy mMockedWindowManagerPolicy; @Mock IBatteryStats mMockedBatteryStats; @Mock WifiP2pManager mMockedWifiP2pManager; @Rule public final ExtendedMockitoRule mExtendedMockitoRule = Loading Loading @@ -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 = Loading Loading @@ -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); Loading