1 package org.robolectric.shadows;
2 
3 import static android.os.Build.VERSION_CODES.M;
4 import static android.os.Build.VERSION_CODES.N;
5 import static android.os.Build.VERSION_CODES.N_MR1;
6 import static android.os.Build.VERSION_CODES.O;
7 import static android.os.Build.VERSION_CODES.P;
8 import static android.os.Build.VERSION_CODES.Q;
9 import static android.os.Build.VERSION_CODES.R;
10 import static android.os.Build.VERSION_CODES.S;
11 import static android.os.Build.VERSION_CODES.TIRAMISU;
12 import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
13 import static com.google.common.base.Preconditions.checkNotNull;
14 
15 import android.accounts.IAccountManager;
16 import android.app.IAlarmManager;
17 import android.app.ILocaleManager;
18 import android.app.INotificationManager;
19 import android.app.ISearchManager;
20 import android.app.IUiModeManager;
21 import android.app.IWallpaperManager;
22 import android.app.admin.IDevicePolicyManager;
23 import android.app.ambientcontext.IAmbientContextManager;
24 import android.app.job.IJobScheduler;
25 import android.app.role.IRoleManager;
26 import android.app.slice.ISliceManager;
27 import android.app.timedetector.ITimeDetectorService;
28 import android.app.timezonedetector.ITimeZoneDetectorService;
29 import android.app.trust.ITrustManager;
30 import android.app.usage.IStorageStatsManager;
31 import android.app.usage.IUsageStatsManager;
32 import android.app.wearable.IWearableSensingManager;
33 import android.bluetooth.BluetoothAdapter;
34 import android.bluetooth.IBluetooth;
35 import android.bluetooth.IBluetoothManager;
36 import android.companion.ICompanionDeviceManager;
37 import android.companion.virtual.IVirtualDeviceManager;
38 import android.content.Context;
39 import android.content.IClipboard;
40 import android.content.IRestrictionsManager;
41 import android.content.integrity.IAppIntegrityManager;
42 import android.content.pm.ICrossProfileApps;
43 import android.content.pm.ILauncherApps;
44 import android.content.pm.IShortcutService;
45 import android.content.rollback.IRollbackManager;
46 import android.credentials.ICredentialManager;
47 import android.hardware.ISensorPrivacyManager;
48 import android.hardware.biometrics.IAuthService;
49 import android.hardware.biometrics.IBiometricService;
50 import android.hardware.display.IColorDisplayManager;
51 import android.hardware.fingerprint.IFingerprintService;
52 import android.hardware.input.IInputManager;
53 import android.hardware.location.IContextHubService;
54 import android.hardware.usb.IUsbManager;
55 import android.location.ICountryDetector;
56 import android.location.ILocationManager;
57 import android.media.IAudioService;
58 import android.media.IMediaRouterService;
59 import android.media.session.ISessionManager;
60 import android.net.IConnectivityManager;
61 import android.net.IIpSecService;
62 import android.net.INetworkPolicyManager;
63 import android.net.INetworkScoreService;
64 import android.net.ITetheringConnector;
65 import android.net.IVpnManager;
66 import android.net.nsd.INsdManager;
67 import android.net.vcn.IVcnManagementService;
68 import android.net.wifi.IWifiManager;
69 import android.net.wifi.IWifiScanner;
70 import android.net.wifi.aware.IWifiAwareManager;
71 import android.net.wifi.p2p.IWifiP2pManager;
72 import android.net.wifi.rtt.IWifiRttManager;
73 import android.nfc.INfcAdapter;
74 import android.os.BatteryStats;
75 import android.os.Binder;
76 import android.os.IBatteryPropertiesRegistrar;
77 import android.os.IBinder;
78 import android.os.IDumpstate;
79 import android.os.IInterface;
80 import android.os.IPowerManager;
81 import android.os.IThermalService;
82 import android.os.IUserManager;
83 import android.os.RemoteException;
84 import android.os.ServiceManager;
85 import android.os.storage.IStorageManager;
86 import android.permission.ILegacyPermissionManager;
87 import android.permission.IPermissionManager;
88 import android.safetycenter.ISafetyCenterManager;
89 import android.security.IFileIntegrityService;
90 import android.speech.IRecognitionServiceManager;
91 import android.uwb.IUwbAdapter;
92 import android.view.IWindowManager;
93 import android.view.contentcapture.IContentCaptureManager;
94 import android.view.translation.ITranslationManager;
95 import com.android.internal.app.IAppOpsService;
96 import com.android.internal.app.IBatteryStats;
97 import com.android.internal.app.ISoundTriggerService;
98 import com.android.internal.app.IVoiceInteractionManagerService;
99 import com.android.internal.appwidget.IAppWidgetService;
100 import com.android.internal.compat.IPlatformCompat;
101 import com.android.internal.os.IDropBoxManagerService;
102 import com.android.internal.statusbar.IStatusBar;
103 import com.android.internal.telephony.ITelephony;
104 import com.android.internal.telephony.ITelephonyRegistry;
105 import com.android.internal.view.IInputMethodManager;
106 import java.util.HashMap;
107 import java.util.HashSet;
108 import java.util.Map;
109 import java.util.Set;
110 import javax.annotation.Nullable;
111 import javax.annotation.concurrent.GuardedBy;
112 import org.robolectric.RuntimeEnvironment;
113 import org.robolectric.annotation.Implementation;
114 import org.robolectric.annotation.Implements;
115 import org.robolectric.annotation.Resetter;
116 import org.robolectric.util.ReflectionHelpers;
117 import org.robolectric.versioning.AndroidVersions.V;
118 
119 /** Shadow for {@link ServiceManager}. */
120 @SuppressWarnings("NewApi")
121 @Implements(value = ServiceManager.class, isInAndroidSdk = false)
122 public class ShadowServiceManager {
123 
124   // A mutable map that contains a list of binder services. It is mutable so entries can be added by
125   // ShadowServiceManager subclasses. This is useful to support prerelease SDKs.
126   protected static final Map<String, BinderService> binderServices = buildBinderServicesMap();
127 
128   @GuardedBy("ShadowServiceManager.class")
129   private static final Set<String> unavailableServices = new HashSet<>();
130 
131   /** Represents the type of implementation to use for the Binder interface */
132   private enum BinderType {
133     /* use ReflectionHelpers.createNullProxy */
134     NULL_PROXY,
135     /* use ReflectionHelpers.createDeepProxy */
136     DEEP_PROXY,
137     /* use ReflectionHelpers.createDelegatingProxy */
138     DELEGATING_PROXY,
139 
140     /**
141      * Use a real concrete implementation of the binder interface. One technique is to use the aidl
142      * compiler generated 'Default' implementation of the binder interface, and use shadows to fill
143      * in the missing functionality and adjust to differences across the supported Android platform
144      * versions
145      */
146     CONCRETE
147   }
148 
149   /**
150    * A data class that holds descriptor information about binder services. It also holds the cached
151    * binder object if it is requested by {@link #getService(String)}.
152    */
153   private static final class BinderService {
154 
155     private final Class<? extends IInterface> clazz;
156     private final String className;
157     private final BinderType binderType;
158     private Binder cachedBinder;
159     private final Object delegate;
160 
BinderService( Class<? extends IInterface> clazz, String className, BinderType binderType, @Nullable Object delegate)161     BinderService(
162         Class<? extends IInterface> clazz,
163         String className,
164         BinderType binderType,
165         @Nullable Object delegate) {
166       this.clazz = clazz;
167       this.className = className;
168       this.binderType = binderType;
169       this.delegate = delegate;
170       if (binderType == BinderType.DELEGATING_PROXY || binderType == BinderType.CONCRETE) {
171         checkNotNull(delegate);
172       }
173     }
174 
175     @GuardedBy("ShadowServiceManager.class")
getBinder()176     IBinder getBinder() {
177       if (cachedBinder == null) {
178         cachedBinder = new Binder();
179         cachedBinder.attachInterface(createBinderImplementation(), className);
180       }
181       return cachedBinder;
182     }
183 
createBinderImplementation()184     private IInterface createBinderImplementation() {
185       switch (binderType) {
186         case NULL_PROXY:
187           return ReflectionHelpers.createNullProxy(clazz);
188         case DEEP_PROXY:
189           return ReflectionHelpers.createDeepProxy(clazz);
190         case DELEGATING_PROXY:
191           return ReflectionHelpers.createDelegatingProxy(clazz, delegate);
192         case CONCRETE:
193           return (IInterface) delegate;
194       }
195       throw new IllegalStateException("unrecognized binder type " + binderType);
196     }
197   }
198 
buildBinderServicesMap()199   private static Map<String, BinderService> buildBinderServicesMap() {
200     Map<String, BinderService> binderServices = new HashMap<>();
201     addBinderService(binderServices, Context.CLIPBOARD_SERVICE, IClipboard.class);
202     addBinderService(binderServices, Context.WIFI_P2P_SERVICE, IWifiP2pManager.class);
203     addBinderService(binderServices, Context.ACCOUNT_SERVICE, IAccountManager.class);
204     addBinderService(binderServices, Context.USB_SERVICE, IUsbManager.class);
205     addBinderService(binderServices, Context.LOCATION_SERVICE, ILocationManager.class);
206     addBinderService(binderServices, Context.INPUT_METHOD_SERVICE, IInputMethodManager.class);
207     addBinderService(binderServices, Context.ALARM_SERVICE, IAlarmManager.class);
208     addBinderService(binderServices, Context.POWER_SERVICE, IPowerManager.class);
209     addBinderService(binderServices, BatteryStats.SERVICE_NAME, IBatteryStats.class);
210     addBinderService(binderServices, Context.DROPBOX_SERVICE, IDropBoxManagerService.class);
211     addBinderService(binderServices, Context.DEVICE_POLICY_SERVICE, IDevicePolicyManager.class);
212     addBinderService(binderServices, Context.TELEPHONY_SERVICE, ITelephony.class);
213     addBinderService(binderServices, Context.CONNECTIVITY_SERVICE, IConnectivityManager.class);
214     addBinderService(binderServices, Context.WIFI_SERVICE, IWifiManager.class);
215     addBinderService(binderServices, Context.SEARCH_SERVICE, ISearchManager.class);
216     addBinderService(binderServices, Context.UI_MODE_SERVICE, IUiModeManager.class);
217     addBinderService(binderServices, Context.NETWORK_POLICY_SERVICE, INetworkPolicyManager.class);
218     addBinderService(binderServices, Context.INPUT_SERVICE, IInputManager.class);
219     addBinderService(binderServices, Context.COUNTRY_DETECTOR, ICountryDetector.class);
220     addBinderService(binderServices, Context.NSD_SERVICE, INsdManager.class);
221     addBinderService(binderServices, Context.AUDIO_SERVICE, IAudioService.class);
222     addBinderService(binderServices, Context.APPWIDGET_SERVICE, IAppWidgetService.class);
223     addBinderService(binderServices, Context.NOTIFICATION_SERVICE, INotificationManager.class);
224     addBinderService(binderServices, Context.WALLPAPER_SERVICE, IWallpaperManager.class);
225     addBinderService(binderServices, Context.BLUETOOTH_SERVICE, IBluetooth.class);
226     addBinderService(binderServices, Context.WINDOW_SERVICE, IWindowManager.class);
227     addBinderService(binderServices, Context.NFC_SERVICE, INfcAdapter.class, BinderType.DEEP_PROXY);
228     addBinderService(binderServices, Context.USER_SERVICE, IUserManager.class);
229     addBinderService(
230         binderServices,
231         BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE,
232         IBluetoothManager.class,
233         BinderType.DELEGATING_PROXY,
234         IBluetoothManagerDelegates.createDelegate());
235 
236     addBinderService(binderServices, Context.APP_OPS_SERVICE, IAppOpsService.class);
237     addBinderService(binderServices, "batteryproperties", IBatteryPropertiesRegistrar.class);
238 
239     addBinderService(binderServices, Context.RESTRICTIONS_SERVICE, IRestrictionsManager.class);
240     addBinderService(binderServices, Context.TRUST_SERVICE, ITrustManager.class);
241     addBinderService(binderServices, Context.JOB_SCHEDULER_SERVICE, IJobScheduler.class);
242     addBinderService(binderServices, Context.NETWORK_SCORE_SERVICE, INetworkScoreService.class);
243     addBinderService(binderServices, Context.USAGE_STATS_SERVICE, IUsageStatsManager.class);
244     addBinderService(binderServices, Context.MEDIA_ROUTER_SERVICE, IMediaRouterService.class);
245     addBinderService(
246         binderServices,
247         Context.MEDIA_SESSION_SERVICE,
248         ISessionManager.class,
249         BinderType.DEEP_PROXY);
250     addBinderService(
251         binderServices,
252         Context.VOICE_INTERACTION_MANAGER_SERVICE,
253         IVoiceInteractionManagerService.class,
254         BinderType.DEEP_PROXY);
255     addBinderService(
256         binderServices,
257         Context.LAUNCHER_APPS_SERVICE,
258         ILauncherApps.class,
259         BinderType.DELEGATING_PROXY,
260         new LauncherAppsDelegate());
261 
262     if (RuntimeEnvironment.getApiLevel() >= M) {
263       addBinderService(binderServices, Context.FINGERPRINT_SERVICE, IFingerprintService.class);
264     }
265     if (RuntimeEnvironment.getApiLevel() >= N) {
266       addBinderService(binderServices, Context.CONTEXTHUB_SERVICE, IContextHubService.class);
267       addBinderService(binderServices, Context.SOUND_TRIGGER_SERVICE, ISoundTriggerService.class);
268       addBinderService(
269           binderServices,
270           Context.WIFI_SCANNING_SERVICE,
271           IWifiScanner.class,
272           BinderType.DELEGATING_PROXY,
273           new WifiScannerDelegate());
274     }
275     if (RuntimeEnvironment.getApiLevel() >= N_MR1) {
276       addBinderService(binderServices, Context.SHORTCUT_SERVICE, IShortcutService.class);
277     }
278     if (RuntimeEnvironment.getApiLevel() >= O) {
279       addBinderService(binderServices, "mount", IStorageManager.class);
280       addBinderService(binderServices, Context.WIFI_AWARE_SERVICE, IWifiAwareManager.class);
281       addBinderService(binderServices, Context.STORAGE_STATS_SERVICE, IStorageStatsManager.class);
282       addBinderService(
283           binderServices, Context.COMPANION_DEVICE_SERVICE, ICompanionDeviceManager.class);
284     } else {
285       addBinderService(binderServices, "mount", "android.os.storage.IMountService");
286     }
287     if (RuntimeEnvironment.getApiLevel() >= P) {
288       addBinderService(binderServices, Context.SLICE_SERVICE, ISliceManager.class);
289       addBinderService(binderServices, Context.CROSS_PROFILE_APPS_SERVICE, ICrossProfileApps.class);
290       addBinderService(binderServices, Context.WIFI_RTT_RANGING_SERVICE, IWifiRttManager.class);
291       addBinderService(binderServices, Context.IPSEC_SERVICE, IIpSecService.class);
292     }
293     if (RuntimeEnvironment.getApiLevel() >= Q) {
294       addBinderService(binderServices, Context.BIOMETRIC_SERVICE, IBiometricService.class);
295       addBinderService(
296           binderServices, Context.CONTENT_CAPTURE_MANAGER_SERVICE, IContentCaptureManager.class);
297       addBinderService(binderServices, Context.ROLE_SERVICE, IRoleManager.class);
298       addBinderService(binderServices, Context.ROLLBACK_SERVICE, IRollbackManager.class);
299       addBinderService(binderServices, Context.THERMAL_SERVICE, IThermalService.class);
300       addBinderService(binderServices, Context.BUGREPORT_SERVICE, IDumpstate.class);
301       addBinderService(binderServices, Context.COLOR_DISPLAY_SERVICE, IColorDisplayManager.class);
302     }
303     if (RuntimeEnvironment.getApiLevel() >= R) {
304       addBinderService(binderServices, Context.APP_INTEGRITY_SERVICE, IAppIntegrityManager.class);
305       addBinderService(binderServices, Context.AUTH_SERVICE, IAuthService.class);
306       addBinderService(binderServices, Context.TETHERING_SERVICE, ITetheringConnector.class);
307       addBinderService(binderServices, "telephony.registry", ITelephonyRegistry.class);
308       addBinderService(binderServices, Context.PLATFORM_COMPAT_SERVICE, IPlatformCompat.class);
309       addBinderService(binderServices, Context.FILE_INTEGRITY_SERVICE, IFileIntegrityService.class);
310     }
311     if (RuntimeEnvironment.getApiLevel() >= S) {
312       addBinderService(binderServices, "permissionmgr", IPermissionManager.class);
313       addBinderService(
314           binderServices, Context.TIME_ZONE_DETECTOR_SERVICE, ITimeZoneDetectorService.class);
315       addBinderService(binderServices, Context.TIME_DETECTOR_SERVICE, ITimeDetectorService.class);
316       addBinderService(
317           binderServices, Context.SPEECH_RECOGNITION_SERVICE, IRecognitionServiceManager.class);
318       addBinderService(
319           binderServices, Context.LEGACY_PERMISSION_SERVICE, ILegacyPermissionManager.class);
320       addBinderService(binderServices, Context.UWB_SERVICE, IUwbAdapter.class);
321       addBinderService(binderServices, Context.VCN_MANAGEMENT_SERVICE, IVcnManagementService.class);
322       addBinderService(
323           binderServices, Context.TRANSLATION_MANAGER_SERVICE, ITranslationManager.class);
324       addBinderService(binderServices, Context.SENSOR_PRIVACY_SERVICE, ISensorPrivacyManager.class);
325       addBinderService(binderServices, Context.VPN_MANAGEMENT_SERVICE, IVpnManager.class);
326     }
327     if (RuntimeEnvironment.getApiLevel() >= TIRAMISU) {
328       addBinderService(
329           binderServices, Context.AMBIENT_CONTEXT_SERVICE, IAmbientContextManager.class);
330       addBinderService(binderServices, Context.LOCALE_SERVICE, ILocaleManager.class);
331       addBinderService(binderServices, Context.SAFETY_CENTER_SERVICE, ISafetyCenterManager.class);
332       addBinderService(binderServices, Context.STATUS_BAR_SERVICE, IStatusBar.class);
333     }
334     if (RuntimeEnvironment.getApiLevel() >= UPSIDE_DOWN_CAKE) {
335       addBinderService(binderServices, Context.VIRTUAL_DEVICE_SERVICE, IVirtualDeviceManager.class);
336       addBinderService(binderServices, Context.CREDENTIAL_SERVICE, ICredentialManager.class);
337       addBinderService(
338           binderServices, Context.WEARABLE_SENSING_SERVICE, IWearableSensingManager.class);
339     }
340     if (RuntimeEnvironment.getApiLevel() >= V.SDK_INT) {
341       // TODO: replace strings with references once compiling against V
342       addBinderService(
343           binderServices,
344           "sensitive_content_protection_service" /* Context.SENSITIVE_CONTENT_PROTECTION_SERVICE */,
345           "android.view.ISensitiveContentProtectionManager"
346           /*ISensitiveContentProtectionManager.class*/ );
347 
348       addBinderService(
349           binderServices,
350           "grammatical_inflection" /* Context.GRAMMATICAL_INFLECTION_SERVICE */,
351           "android.app.IGrammaticalInflectionManager" /* IGrammaticalInflectionManager.class */);
352 
353       addBinderServiceIfClassExists(
354           binderServices,
355           "protolog_configuration" /* Context.PROTOLOG_CONFIGURATION_SERVICE, */,
356           "com.android.internal.protolog.ProtoLogConfigurationService"
357           /* new ProtoLogConfigurationServiceImpl.class */ );
358     }
359 
360     return binderServices;
361   }
362 
addBinderService( Map<String, BinderService> binderServices, String name, Class<? extends IInterface> clazz)363   protected static void addBinderService(
364       Map<String, BinderService> binderServices, String name, Class<? extends IInterface> clazz) {
365     addBinderService(
366         binderServices, name, clazz, clazz.getCanonicalName(), BinderType.NULL_PROXY, null);
367   }
368 
addBinderService( Map<String, BinderService> binderServices, String name, Class<? extends IInterface> clazz, BinderType proxyType)369   private static void addBinderService(
370       Map<String, BinderService> binderServices,
371       String name,
372       Class<? extends IInterface> clazz,
373       BinderType proxyType) {
374     addBinderService(binderServices, name, clazz, clazz.getCanonicalName(), proxyType, null);
375   }
376 
addBinderService( Map<String, BinderService> binderServices, String name, String className)377   private static void addBinderService(
378       Map<String, BinderService> binderServices, String name, String className) {
379     Class<? extends IInterface> clazz;
380     try {
381       clazz = Class.forName(className).asSubclass(IInterface.class);
382     } catch (ClassNotFoundException e) {
383       throw new RuntimeException(e);
384     }
385     addBinderService(binderServices, name, clazz, className, BinderType.NULL_PROXY, null);
386   }
387 
addBinderService( Map<String, BinderService> binderServices, String name, Class<? extends IInterface> clazz, BinderType proxyType, @Nullable Object delegate)388   private static void addBinderService(
389       Map<String, BinderService> binderServices,
390       String name,
391       Class<? extends IInterface> clazz,
392       BinderType proxyType,
393       @Nullable Object delegate) {
394     addBinderService(binderServices, name, clazz, clazz.getCanonicalName(), proxyType, delegate);
395   }
396 
addBinderService( Map<String, BinderService> binderServices, String name, Class<? extends IInterface> clazz, String className, BinderType proxyType, @Nullable Object delegate)397   private static void addBinderService(
398       Map<String, BinderService> binderServices,
399       String name,
400       Class<? extends IInterface> clazz,
401       String className,
402       BinderType proxyType,
403       @Nullable Object delegate) {
404     binderServices.put(name, new BinderService(clazz, className, proxyType, delegate));
405   }
406 
addBinderService( String name, Class<? extends IInterface> clazz, IInterface service)407   public static void addBinderService(
408       String name, Class<? extends IInterface> clazz, IInterface service) {
409     binderServices.put(
410         name, new BinderService(clazz, clazz.getCanonicalName(), BinderType.CONCRETE, service));
411   }
412 
addBinderServiceIfClassExists( Map<String, BinderService> binderServices, String name, String className)413   private static void addBinderServiceIfClassExists(
414       Map<String, BinderService> binderServices, String name, String className) {
415     Class<? extends IInterface> clazz;
416     try {
417       clazz = Class.forName(className).asSubclass(IInterface.class);
418       addBinderService(binderServices, name, clazz, className, BinderType.NULL_PROXY, null);
419     } catch (ClassNotFoundException e) {
420       return;
421     }
422   }
423 
424   /**
425    * Returns the {@link IBinder} associated with the given system service. If the given service is
426    * set to unavailable in {@link #setServiceAvailability}, {@code null} will be returned.
427    */
428   @Implementation
getService(String name)429   protected static IBinder getService(String name) {
430     synchronized (ShadowServiceManager.class) {
431       if (unavailableServices.contains(name)) {
432         return null;
433       }
434       return getBinderForService(name);
435     }
436   }
437 
438   @Implementation
addService(String name, IBinder service)439   protected static void addService(String name, IBinder service) {}
440 
441   /**
442    * Same as {@link #getService}.
443    *
444    * <p>The real implementation of {@link #checkService} differs from {@link #getService} in that it
445    * is not a blocking call; so it is more likely to return {@code null} in cases where the service
446    * isn't available (whereas {@link #getService} will block until it becomes available, until a
447    * timeout or error happens).
448    */
449   @Implementation
checkService(String name)450   protected static IBinder checkService(String name) {
451     synchronized (ShadowServiceManager.class) {
452       if (unavailableServices.contains(name)) {
453         return null;
454       }
455       return getBinderForService(name);
456     }
457   }
458 
459   @Implementation
listServices()460   protected static String[] listServices() throws RemoteException {
461     return null;
462   }
463 
464   @Implementation
initServiceCache(Map<String, IBinder> cache)465   protected static void initServiceCache(Map<String, IBinder> cache) {}
466 
467   /**
468    * Sets the availability of the given system service. If the service is set as unavailable,
469    * subsequent calls to {@link Context#getSystemService} for that service will return {@code null}.
470    *
471    * <p>A service is considered available by default.
472    */
setServiceAvailability(String service, boolean available)473   public static synchronized void setServiceAvailability(String service, boolean available) {
474     if (available) {
475       unavailableServices.remove(service);
476     } else {
477       unavailableServices.add(service);
478     }
479   }
480 
481   @GuardedBy("ShadowServiceManager.class")
482   @Nullable
getBinderForService(String name)483   private static IBinder getBinderForService(String name) {
484     BinderService binderService = binderServices.get(name);
485     if (binderService == null) {
486       return null;
487     }
488     return binderService.getBinder();
489   }
490 
491   @Resetter
reset()492   public static synchronized void reset() {
493     unavailableServices.clear();
494   }
495 }
496