blob: 778e1968c641ffc7d10e9f7695980293719e99e2 [file] [log] [blame]
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;
import static android.os.Build.VERSION_CODES.N_MR1;
import static android.os.Build.VERSION_CODES.O;
import static android.os.Build.VERSION_CODES.P;
import static android.os.Build.VERSION_CODES.Q;
import static android.os.Build.VERSION_CODES.R;
import static android.os.Build.VERSION_CODES.S;
import static android.os.Build.VERSION_CODES.TIRAMISU;
import android.accounts.IAccountManager;
import android.app.IAlarmManager;
import android.app.ILocaleManager;
import android.app.INotificationManager;
import android.app.ISearchManager;
import android.app.IUiModeManager;
import android.app.IWallpaperManager;
import android.app.admin.IDevicePolicyManager;
import android.app.ambientcontext.IAmbientContextManager;
import android.app.job.IJobScheduler;
import android.app.role.IRoleManager;
import android.app.slice.ISliceManager;
import android.app.timedetector.ITimeDetectorService;
import android.app.timezonedetector.ITimeZoneDetectorService;
import android.app.trust.ITrustManager;
import android.app.usage.IStorageStatsManager;
import android.app.usage.IUsageStatsManager;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.IBluetooth;
import android.bluetooth.IBluetoothManager;
import android.companion.ICompanionDeviceManager;
import android.content.Context;
import android.content.IClipboard;
import android.content.IRestrictionsManager;
import android.content.integrity.IAppIntegrityManager;
import android.content.pm.ICrossProfileApps;
import android.content.pm.IShortcutService;
import android.content.rollback.IRollbackManager;
import android.hardware.biometrics.IAuthService;
import android.hardware.biometrics.IBiometricService;
import android.hardware.fingerprint.IFingerprintService;
import android.hardware.input.IInputManager;
import android.hardware.location.IContextHubService;
import android.hardware.usb.IUsbManager;
import android.location.ICountryDetector;
import android.location.ILocationManager;
import android.media.IAudioService;
import android.media.IMediaRouterService;
import android.media.session.ISessionManager;
import android.net.IConnectivityManager;
import android.net.IIpSecService;
import android.net.INetworkPolicyManager;
import android.net.INetworkScoreService;
import android.net.ITetheringConnector;
import android.net.nsd.INsdManager;
import android.net.vcn.IVcnManagementService;
import android.net.wifi.IWifiManager;
import android.net.wifi.aware.IWifiAwareManager;
import android.net.wifi.p2p.IWifiP2pManager;
import android.net.wifi.rtt.IWifiRttManager;
import android.nfc.INfcAdapter;
import android.os.BatteryStats;
import android.os.Binder;
import android.os.IBatteryPropertiesRegistrar;
import android.os.IBinder;
import android.os.IDumpstate;
import android.os.IInterface;
import android.os.IPowerManager;
import android.os.IThermalService;
import android.os.IUserManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.storage.IStorageManager;
import android.permission.ILegacyPermissionManager;
import android.permission.IPermissionManager;
import android.safetycenter.ISafetyCenterManager;
import android.speech.IRecognitionServiceManager;
import android.uwb.IUwbAdapter;
import android.view.IWindowManager;
import android.view.contentcapture.IContentCaptureManager;
import android.view.translation.ITranslationManager;
import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IBatteryStats;
import com.android.internal.appwidget.IAppWidgetService;
import com.android.internal.os.IDropBoxManagerService;
import com.android.internal.statusbar.IStatusBar;
import com.android.internal.telephony.ITelephony;
import com.android.internal.telephony.ITelephonyRegistry;
import com.android.internal.view.IInputMethodManager;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.Resetter;
import org.robolectric.util.ReflectionHelpers;
import android.companion.virtual.IVirtualDeviceManager;
/** Shadow for {@link ServiceManager}. */
@SuppressWarnings("NewApi")
@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);
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);
}
if (RuntimeEnvironment.getApiLevel() >= M) {
addBinderService(Context.FINGERPRINT_SERVICE, IFingerprintService.class);
}
if (RuntimeEnvironment.getApiLevel() >= N) {
addBinderService(Context.CONTEXTHUB_SERVICE, IContextHubService.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);
}
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);
}
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);
}
}
/**
* 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 final Class<? extends IInterface> clazz;
private final String className;
private final boolean useDeepBinder;
private Binder cachedBinder;
BinderService(Class<? extends IInterface> clazz, String className, boolean useDeepBinder) {
this.clazz = clazz;
this.className = className;
this.useDeepBinder = useDeepBinder;
}
// Needs to be synchronized in case multiple threads call ServiceManager.getService
// concurrently.
synchronized IBinder getBinder() {
if (cachedBinder == null) {
cachedBinder = new Binder();
cachedBinder.attachInterface(
useDeepBinder
? ReflectionHelpers.createDeepProxy(clazz)
: ReflectionHelpers.createNullProxy(clazz),
className);
}
return cachedBinder;
}
}
protected static void addBinderService(String name, Class<? extends IInterface> clazz) {
addBinderService(name, clazz, clazz.getCanonicalName(), false);
}
protected static void addBinderService(
String name, Class<? extends IInterface> clazz, boolean useDeepBinder) {
addBinderService(name, clazz, clazz.getCanonicalName(), useDeepBinder);
}
protected static void addBinderService(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);
}
protected static void addBinderService(
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.
*/
@Implementation
protected static IBinder getService(String name) {
if (unavailableServices.contains(name)) {
return null;
}
BinderService binderService = binderServices.get(name);
if (binderService == null) {
return null;
}
return binderService.getBinder();
}
@Implementation
protected static void addService(String name, IBinder service) {}
@Implementation
protected static IBinder checkService(String name) {
return null;
}
@Implementation
protected static String[] listServices() throws RemoteException {
return null;
}
@Implementation
protected static void initServiceCache(Map<String, IBinder> cache) {}
/**
* 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}.
*/
public static void setServiceAvailability(String service, boolean available) {
if (available) {
unavailableServices.remove(service);
} else {
unavailableServices.add(service);
}
}
@Resetter
public static void reset() {
unavailableServices.clear();
}
}