diff options
Diffstat (limited to 'shadows/framework/src/main/java/org/robolectric/shadows/ShadowServiceManager.java')
-rw-r--r-- | shadows/framework/src/main/java/org/robolectric/shadows/ShadowServiceManager.java | 327 |
1 files changed, 184 insertions, 143 deletions
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowServiceManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowServiceManager.java index 1dfbfeccf..7abe78b02 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowServiceManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowServiceManager.java @@ -1,8 +1,5 @@ package org.robolectric.shadows; -import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1; -import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR2; -import static android.os.Build.VERSION_CODES.KITKAT; import static android.os.Build.VERSION_CODES.LOLLIPOP; import static android.os.Build.VERSION_CODES.M; import static android.os.Build.VERSION_CODES.N; @@ -105,6 +102,8 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; +import javax.annotation.Nullable; +import javax.annotation.concurrent.GuardedBy; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; @@ -117,128 +116,18 @@ import android.companion.virtual.IVirtualDeviceManager; @Implements(value = ServiceManager.class, isInAndroidSdk = false) public class ShadowServiceManager { - private static final Map<String, BinderService> binderServices = new HashMap<>(); - private static final Set<String> unavailableServices = new HashSet<>(); - - static { - addBinderService(Context.CLIPBOARD_SERVICE, IClipboard.class); - addBinderService(Context.WIFI_P2P_SERVICE, IWifiP2pManager.class); - addBinderService(Context.ACCOUNT_SERVICE, IAccountManager.class); - addBinderService(Context.USB_SERVICE, IUsbManager.class); - addBinderService(Context.LOCATION_SERVICE, ILocationManager.class); - addBinderService(Context.INPUT_METHOD_SERVICE, IInputMethodManager.class); - addBinderService(Context.ALARM_SERVICE, IAlarmManager.class); - addBinderService(Context.POWER_SERVICE, IPowerManager.class); - addBinderService(BatteryStats.SERVICE_NAME, IBatteryStats.class); - addBinderService(Context.DROPBOX_SERVICE, IDropBoxManagerService.class); - addBinderService(Context.DEVICE_POLICY_SERVICE, IDevicePolicyManager.class); - addBinderService(Context.TELEPHONY_SERVICE, ITelephony.class); - addBinderService(Context.CONNECTIVITY_SERVICE, IConnectivityManager.class); - addBinderService(Context.WIFI_SERVICE, IWifiManager.class); - addBinderService(Context.SEARCH_SERVICE, ISearchManager.class); - addBinderService(Context.UI_MODE_SERVICE, IUiModeManager.class); - addBinderService(Context.NETWORK_POLICY_SERVICE, INetworkPolicyManager.class); - addBinderService(Context.INPUT_SERVICE, IInputManager.class); - addBinderService(Context.COUNTRY_DETECTOR, ICountryDetector.class); - addBinderService(Context.NSD_SERVICE, INsdManager.class); - addBinderService(Context.AUDIO_SERVICE, IAudioService.class); - addBinderService(Context.APPWIDGET_SERVICE, IAppWidgetService.class); - addBinderService(Context.NOTIFICATION_SERVICE, INotificationManager.class); - addBinderService(Context.WALLPAPER_SERVICE, IWallpaperManager.class); - addBinderService(Context.BLUETOOTH_SERVICE, IBluetooth.class); - addBinderService(Context.WINDOW_SERVICE, IWindowManager.class); - addBinderService(Context.NFC_SERVICE, INfcAdapter.class, true); - addBinderService(Context.VIRTUAL_DEVICE_SERVICE, IVirtualDeviceManager.class); + // A mutable map that contains a list of binder services. It is mutable so entries can be added by + // ShadowServiceManager subclasses. This is useful to support prerelease SDKs. + protected static final Map<String, BinderService> binderServices = buildBinderServicesMap(); - if (RuntimeEnvironment.getApiLevel() >= JELLY_BEAN_MR1) { - addBinderService(Context.USER_SERVICE, IUserManager.class); - addBinderService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE, IBluetoothManager.class); - } - if (RuntimeEnvironment.getApiLevel() >= JELLY_BEAN_MR2) { - addBinderService(Context.APP_OPS_SERVICE, IAppOpsService.class); - } - if (RuntimeEnvironment.getApiLevel() >= KITKAT) { - addBinderService("batteryproperties", IBatteryPropertiesRegistrar.class); - } - if (RuntimeEnvironment.getApiLevel() >= LOLLIPOP) { - addBinderService(Context.RESTRICTIONS_SERVICE, IRestrictionsManager.class); - addBinderService(Context.TRUST_SERVICE, ITrustManager.class); - addBinderService(Context.JOB_SCHEDULER_SERVICE, IJobScheduler.class); - addBinderService(Context.NETWORK_SCORE_SERVICE, INetworkScoreService.class); - addBinderService(Context.USAGE_STATS_SERVICE, IUsageStatsManager.class); - addBinderService(Context.MEDIA_ROUTER_SERVICE, IMediaRouterService.class); - addBinderService(Context.MEDIA_SESSION_SERVICE, ISessionManager.class, true); - addBinderService( - Context.VOICE_INTERACTION_MANAGER_SERVICE, IVoiceInteractionManagerService.class, true); - } - if (RuntimeEnvironment.getApiLevel() >= M) { - addBinderService(Context.FINGERPRINT_SERVICE, IFingerprintService.class); - } - if (RuntimeEnvironment.getApiLevel() >= N) { - addBinderService(Context.CONTEXTHUB_SERVICE, IContextHubService.class); - addBinderService(Context.SOUND_TRIGGER_SERVICE, ISoundTriggerService.class); - } - if (RuntimeEnvironment.getApiLevel() >= N_MR1) { - addBinderService(Context.SHORTCUT_SERVICE, IShortcutService.class); - } - if (RuntimeEnvironment.getApiLevel() >= O) { - addBinderService("mount", IStorageManager.class); - addBinderService(Context.WIFI_AWARE_SERVICE, IWifiAwareManager.class); - addBinderService(Context.STORAGE_STATS_SERVICE, IStorageStatsManager.class); - addBinderService(Context.COMPANION_DEVICE_SERVICE, ICompanionDeviceManager.class); - } else { - addBinderService("mount", "android.os.storage.IMountService"); - } - if (RuntimeEnvironment.getApiLevel() >= P) { - addBinderService(Context.SLICE_SERVICE, ISliceManager.class); - addBinderService(Context.CROSS_PROFILE_APPS_SERVICE, ICrossProfileApps.class); - addBinderService(Context.WIFI_RTT_RANGING_SERVICE, IWifiRttManager.class); - addBinderService(Context.IPSEC_SERVICE, IIpSecService.class); - } - if (RuntimeEnvironment.getApiLevel() >= Q) { - addBinderService(Context.BIOMETRIC_SERVICE, IBiometricService.class); - addBinderService(Context.CONTENT_CAPTURE_MANAGER_SERVICE, IContentCaptureManager.class); - addBinderService(Context.ROLE_SERVICE, IRoleManager.class); - addBinderService(Context.ROLLBACK_SERVICE, IRollbackManager.class); - addBinderService(Context.THERMAL_SERVICE, IThermalService.class); - addBinderService(Context.BUGREPORT_SERVICE, IDumpstate.class); - } - if (RuntimeEnvironment.getApiLevel() >= R) { - addBinderService(Context.APP_INTEGRITY_SERVICE, IAppIntegrityManager.class); - addBinderService(Context.AUTH_SERVICE, IAuthService.class); - addBinderService(Context.TETHERING_SERVICE, ITetheringConnector.class); - addBinderService("telephony.registry", ITelephonyRegistry.class); - addBinderService(Context.PLATFORM_COMPAT_SERVICE, IPlatformCompat.class); - } - if (RuntimeEnvironment.getApiLevel() >= S) { - addBinderService("permissionmgr", IPermissionManager.class); - addBinderService(Context.TIME_ZONE_DETECTOR_SERVICE, ITimeZoneDetectorService.class); - addBinderService(Context.TIME_DETECTOR_SERVICE, ITimeDetectorService.class); - addBinderService(Context.SPEECH_RECOGNITION_SERVICE, IRecognitionServiceManager.class); - addBinderService(Context.LEGACY_PERMISSION_SERVICE, ILegacyPermissionManager.class); - addBinderService(Context.UWB_SERVICE, IUwbAdapter.class); - addBinderService(Context.VCN_MANAGEMENT_SERVICE, IVcnManagementService.class); - addBinderService(Context.TRANSLATION_MANAGER_SERVICE, ITranslationManager.class); - addBinderService(Context.SENSOR_PRIVACY_SERVICE, ISensorPrivacyManager.class); - addBinderService(Context.VPN_MANAGEMENT_SERVICE, IVpnManager.class); - } - if (RuntimeEnvironment.getApiLevel() >= TIRAMISU) { - addBinderService(Context.AMBIENT_CONTEXT_SERVICE, IAmbientContextManager.class); - addBinderService(Context.LOCALE_SERVICE, ILocaleManager.class); - addBinderService(Context.SAFETY_CENTER_SERVICE, ISafetyCenterManager.class); - addBinderService(Context.STATUS_BAR_SERVICE, IStatusBar.class); - } - if (RuntimeEnvironment.getApiLevel() >= UPSIDE_DOWN_CAKE) { - addBinderService(Context.VIRTUAL_DEVICE_SERVICE, IVirtualDeviceManager.class); - addBinderService(Context.WEARABLE_SENSING_SERVICE, IWearableSensingManager.class); - } - } + @GuardedBy("ShadowServiceManager.class") + private static final Set<String> unavailableServices = new HashSet<>(); /** * A data class that holds descriptor information about binder services. It also holds the cached * binder object if it is requested by {@link #getService(String)}. */ - private static class BinderService { + private static final class BinderService { private final Class<? extends IInterface> clazz; private final String className; @@ -251,9 +140,8 @@ public class ShadowServiceManager { this.useDeepBinder = useDeepBinder; } - // Needs to be synchronized in case multiple threads call ServiceManager.getService - // concurrently. - synchronized IBinder getBinder() { + @GuardedBy("ShadowServiceManager.class") + IBinder getBinder() { if (cachedBinder == null) { cachedBinder = new Binder(); cachedBinder.attachInterface( @@ -266,52 +154,193 @@ public class ShadowServiceManager { } } - protected static void addBinderService(String name, Class<? extends IInterface> clazz) { - addBinderService(name, clazz, clazz.getCanonicalName(), false); + private static Map<String, BinderService> buildBinderServicesMap() { + Map<String, BinderService> binderServices = new HashMap<>(); + addBinderService(binderServices, Context.CLIPBOARD_SERVICE, IClipboard.class); + addBinderService(binderServices, Context.WIFI_P2P_SERVICE, IWifiP2pManager.class); + addBinderService(binderServices, Context.ACCOUNT_SERVICE, IAccountManager.class); + addBinderService(binderServices, Context.USB_SERVICE, IUsbManager.class); + addBinderService(binderServices, Context.LOCATION_SERVICE, ILocationManager.class); + addBinderService(binderServices, Context.INPUT_METHOD_SERVICE, IInputMethodManager.class); + addBinderService(binderServices, Context.ALARM_SERVICE, IAlarmManager.class); + addBinderService(binderServices, Context.POWER_SERVICE, IPowerManager.class); + addBinderService(binderServices, BatteryStats.SERVICE_NAME, IBatteryStats.class); + addBinderService(binderServices, Context.DROPBOX_SERVICE, IDropBoxManagerService.class); + addBinderService(binderServices, Context.DEVICE_POLICY_SERVICE, IDevicePolicyManager.class); + addBinderService(binderServices, Context.TELEPHONY_SERVICE, ITelephony.class); + addBinderService(binderServices, Context.CONNECTIVITY_SERVICE, IConnectivityManager.class); + addBinderService(binderServices, Context.WIFI_SERVICE, IWifiManager.class); + addBinderService(binderServices, Context.SEARCH_SERVICE, ISearchManager.class); + addBinderService(binderServices, Context.UI_MODE_SERVICE, IUiModeManager.class); + addBinderService(binderServices, Context.NETWORK_POLICY_SERVICE, INetworkPolicyManager.class); + addBinderService(binderServices, Context.INPUT_SERVICE, IInputManager.class); + addBinderService(binderServices, Context.COUNTRY_DETECTOR, ICountryDetector.class); + addBinderService(binderServices, Context.NSD_SERVICE, INsdManager.class); + addBinderService(binderServices, Context.AUDIO_SERVICE, IAudioService.class); + addBinderService(binderServices, Context.APPWIDGET_SERVICE, IAppWidgetService.class); + addBinderService(binderServices, Context.NOTIFICATION_SERVICE, INotificationManager.class); + addBinderService(binderServices, Context.WALLPAPER_SERVICE, IWallpaperManager.class); + addBinderService(binderServices, Context.BLUETOOTH_SERVICE, IBluetooth.class); + addBinderService(binderServices, Context.WINDOW_SERVICE, IWindowManager.class); + addBinderService(binderServices, Context.NFC_SERVICE, INfcAdapter.class, true); + addBinderService(binderServices, Context.USER_SERVICE, IUserManager.class); + addBinderService( + binderServices, BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE, IBluetoothManager.class); + addBinderService(binderServices, Context.APP_OPS_SERVICE, IAppOpsService.class); + addBinderService(binderServices, "batteryproperties", IBatteryPropertiesRegistrar.class); + + if (RuntimeEnvironment.getApiLevel() >= LOLLIPOP) { + addBinderService(binderServices, Context.RESTRICTIONS_SERVICE, IRestrictionsManager.class); + addBinderService(binderServices, Context.TRUST_SERVICE, ITrustManager.class); + addBinderService(binderServices, Context.JOB_SCHEDULER_SERVICE, IJobScheduler.class); + addBinderService(binderServices, Context.NETWORK_SCORE_SERVICE, INetworkScoreService.class); + addBinderService(binderServices, Context.USAGE_STATS_SERVICE, IUsageStatsManager.class); + addBinderService(binderServices, Context.MEDIA_ROUTER_SERVICE, IMediaRouterService.class); + addBinderService(binderServices, Context.MEDIA_SESSION_SERVICE, ISessionManager.class, true); + addBinderService( + binderServices, + Context.VOICE_INTERACTION_MANAGER_SERVICE, + IVoiceInteractionManagerService.class, + true); + } + if (RuntimeEnvironment.getApiLevel() >= M) { + addBinderService(binderServices, Context.FINGERPRINT_SERVICE, IFingerprintService.class); + } + if (RuntimeEnvironment.getApiLevel() >= N) { + addBinderService(binderServices, Context.CONTEXTHUB_SERVICE, IContextHubService.class); + addBinderService(binderServices, Context.SOUND_TRIGGER_SERVICE, ISoundTriggerService.class); + } + if (RuntimeEnvironment.getApiLevel() >= N_MR1) { + addBinderService(binderServices, Context.SHORTCUT_SERVICE, IShortcutService.class); + } + if (RuntimeEnvironment.getApiLevel() >= O) { + addBinderService(binderServices, "mount", IStorageManager.class); + addBinderService(binderServices, Context.WIFI_AWARE_SERVICE, IWifiAwareManager.class); + addBinderService(binderServices, Context.STORAGE_STATS_SERVICE, IStorageStatsManager.class); + addBinderService( + binderServices, Context.COMPANION_DEVICE_SERVICE, ICompanionDeviceManager.class); + } else { + addBinderService(binderServices, "mount", "android.os.storage.IMountService"); + } + if (RuntimeEnvironment.getApiLevel() >= P) { + addBinderService(binderServices, Context.SLICE_SERVICE, ISliceManager.class); + addBinderService(binderServices, Context.CROSS_PROFILE_APPS_SERVICE, ICrossProfileApps.class); + addBinderService(binderServices, Context.WIFI_RTT_RANGING_SERVICE, IWifiRttManager.class); + addBinderService(binderServices, Context.IPSEC_SERVICE, IIpSecService.class); + } + if (RuntimeEnvironment.getApiLevel() >= Q) { + addBinderService(binderServices, Context.BIOMETRIC_SERVICE, IBiometricService.class); + addBinderService( + binderServices, Context.CONTENT_CAPTURE_MANAGER_SERVICE, IContentCaptureManager.class); + addBinderService(binderServices, Context.ROLE_SERVICE, IRoleManager.class); + addBinderService(binderServices, Context.ROLLBACK_SERVICE, IRollbackManager.class); + addBinderService(binderServices, Context.THERMAL_SERVICE, IThermalService.class); + addBinderService(binderServices, Context.BUGREPORT_SERVICE, IDumpstate.class); + } + if (RuntimeEnvironment.getApiLevel() >= R) { + addBinderService(binderServices, Context.APP_INTEGRITY_SERVICE, IAppIntegrityManager.class); + addBinderService(binderServices, Context.AUTH_SERVICE, IAuthService.class); + addBinderService(binderServices, Context.TETHERING_SERVICE, ITetheringConnector.class); + addBinderService(binderServices, "telephony.registry", ITelephonyRegistry.class); + addBinderService(binderServices, Context.PLATFORM_COMPAT_SERVICE, IPlatformCompat.class); + } + if (RuntimeEnvironment.getApiLevel() >= S) { + addBinderService(binderServices, "permissionmgr", IPermissionManager.class); + addBinderService( + binderServices, Context.TIME_ZONE_DETECTOR_SERVICE, ITimeZoneDetectorService.class); + addBinderService(binderServices, Context.TIME_DETECTOR_SERVICE, ITimeDetectorService.class); + addBinderService( + binderServices, Context.SPEECH_RECOGNITION_SERVICE, IRecognitionServiceManager.class); + addBinderService( + binderServices, Context.LEGACY_PERMISSION_SERVICE, ILegacyPermissionManager.class); + addBinderService(binderServices, Context.UWB_SERVICE, IUwbAdapter.class); + addBinderService(binderServices, Context.VCN_MANAGEMENT_SERVICE, IVcnManagementService.class); + addBinderService( + binderServices, Context.TRANSLATION_MANAGER_SERVICE, ITranslationManager.class); + addBinderService(binderServices, Context.SENSOR_PRIVACY_SERVICE, ISensorPrivacyManager.class); + addBinderService(binderServices, Context.VPN_MANAGEMENT_SERVICE, IVpnManager.class); + } + if (RuntimeEnvironment.getApiLevel() >= TIRAMISU) { + addBinderService( + binderServices, Context.AMBIENT_CONTEXT_SERVICE, IAmbientContextManager.class); + addBinderService(binderServices, Context.LOCALE_SERVICE, ILocaleManager.class); + addBinderService(binderServices, Context.SAFETY_CENTER_SERVICE, ISafetyCenterManager.class); + addBinderService(binderServices, Context.STATUS_BAR_SERVICE, IStatusBar.class); + } + if (RuntimeEnvironment.getApiLevel() >= UPSIDE_DOWN_CAKE) { + addBinderService(binderServices, Context.VIRTUAL_DEVICE_SERVICE, IVirtualDeviceManager.class); + addBinderService( + binderServices, Context.WEARABLE_SENSING_SERVICE, IWearableSensingManager.class); + } + return binderServices; } protected static void addBinderService( - String name, Class<? extends IInterface> clazz, boolean useDeepBinder) { - addBinderService(name, clazz, clazz.getCanonicalName(), useDeepBinder); + Map<String, BinderService> binderServices, String name, Class<? extends IInterface> clazz) { + addBinderService(binderServices, name, clazz, clazz.getCanonicalName(), false); + } + + private static void addBinderService( + Map<String, BinderService> binderServices, + String name, + Class<? extends IInterface> clazz, + boolean useDeepBinder) { + addBinderService(binderServices, name, clazz, clazz.getCanonicalName(), useDeepBinder); } - protected static void addBinderService(String name, String className) { + private static void addBinderService( + Map<String, BinderService> binderServices, String name, String className) { Class<? extends IInterface> clazz; try { clazz = Class.forName(className).asSubclass(IInterface.class); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } - addBinderService(name, clazz, className, false); + addBinderService(binderServices, name, clazz, className, false); } - protected static void addBinderService( - String name, Class<? extends IInterface> clazz, String className, boolean useDeepBinder) { + private static void addBinderService( + Map<String, BinderService> binderServices, + String name, + Class<? extends IInterface> clazz, + String className, + boolean useDeepBinder) { binderServices.put(name, new BinderService(clazz, className, useDeepBinder)); } + /** - * Returns the binder associated with the given system service. If the given service is set to - * unavailable in {@link #setServiceAvailability}, {@code null} will be returned. + * Returns the {@link IBinder} associated with the given system service. If the given service is + * set to unavailable in {@link #setServiceAvailability}, {@code null} will be returned. */ @Implementation protected static IBinder getService(String name) { - if (unavailableServices.contains(name)) { - return null; - } - BinderService binderService = binderServices.get(name); - if (binderService == null) { - return null; + synchronized (ShadowServiceManager.class) { + if (unavailableServices.contains(name)) { + return null; + } + return getBinderForService(name); } - - return binderService.getBinder(); } @Implementation protected static void addService(String name, IBinder service) {} + /** + * Same as {@link #getService}. + * + * <p>The real implementation of {@link #checkService} differs from {@link #getService} in that it + * is not a blocking call; so it is more likely to return {@code null} in cases where the service + * isn't available (whereas {@link #getService} will block until it becomes available, until a + * timeout or error happens). + */ @Implementation protected static IBinder checkService(String name) { - return null; + synchronized (ShadowServiceManager.class) { + if (unavailableServices.contains(name)) { + return null; + } + return getBinderForService(name); + } } @Implementation @@ -325,8 +354,10 @@ public class ShadowServiceManager { /** * Sets the availability of the given system service. If the service is set as unavailable, * subsequent calls to {@link Context#getSystemService} for that service will return {@code null}. + * + * <p>A service is considered available by default. */ - public static void setServiceAvailability(String service, boolean available) { + public static synchronized void setServiceAvailability(String service, boolean available) { if (available) { unavailableServices.remove(service); } else { @@ -334,8 +365,18 @@ public class ShadowServiceManager { } } + @GuardedBy("ShadowServiceManager.class") + @Nullable + private static IBinder getBinderForService(String name) { + BinderService binderService = binderServices.get(name); + if (binderService == null) { + return null; + } + return binderService.getBinder(); + } + @Resetter - public static void reset() { + public static synchronized void reset() { unavailableServices.clear(); } } |