aboutsummaryrefslogtreecommitdiff
path: root/shadows/framework/src/main/java/org/robolectric/shadows/ShadowServiceManager.java
diff options
context:
space:
mode:
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.java327
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();
}
}