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