1 package org.robolectric.shadows;
2 
3 import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
4 import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR2;
5 import static android.os.Build.VERSION_CODES.KITKAT;
6 import static android.os.Build.VERSION_CODES.LOLLIPOP;
7 import static android.os.Build.VERSION_CODES.M;
8 import static android.os.Build.VERSION_CODES.N_MR1;
9 import static android.os.Build.VERSION_CODES.O;
10 import static android.os.Build.VERSION_CODES.P;
11 import static android.os.Build.VERSION_CODES.Q;
12 import static android.os.Build.VERSION_CODES.R;
13 import static android.os.Build.VERSION_CODES.S;
14 
15 import android.accounts.IAccountManager;
16 import android.app.IAlarmManager;
17 import android.app.INotificationManager;
18 import android.app.ISearchManager;
19 import android.app.admin.IDevicePolicyManager;
20 import android.app.job.IJobScheduler;
21 import android.app.slice.ISliceManager;
22 import android.app.trust.ITrustManager;
23 import android.app.usage.IUsageStatsManager;
24 import android.content.Context;
25 import android.content.IClipboard;
26 import android.content.IRestrictionsManager;
27 import android.content.pm.ICrossProfileApps;
28 import android.content.pm.IShortcutService;
29 import android.hardware.display.IColorDisplayManager;
30 import android.hardware.fingerprint.IFingerprintService;
31 import android.hardware.input.IInputManager;
32 import android.hardware.usb.IUsbManager;
33 import android.location.ICountryDetector;
34 import android.location.ILocationManager;
35 import android.media.IAudioService;
36 import android.media.IMediaRouterService;
37 import android.media.session.ISessionManager;
38 import android.net.IConnectivityManager;
39 import android.net.INetworkScoreService;
40 import android.net.ITetheringConnector;
41 import android.net.IVpnManager;
42 import android.net.nsd.INsdManager;
43 import android.net.wifi.IWifiManager;
44 import android.net.wifi.p2p.IWifiP2pManager;
45 import android.os.BatteryStats;
46 import android.os.Binder;
47 import android.os.IBatteryPropertiesRegistrar;
48 import android.os.IBinder;
49 import android.os.IInterface;
50 import android.os.IPowerManager;
51 import android.os.IThermalService;
52 import android.os.IUserManager;
53 import android.os.RemoteException;
54 import android.os.ServiceManager;
55 import android.os.storage.IStorageManager;
56 import android.permission.IPermissionManager;
57 import android.service.persistentdata.IPersistentDataBlockService;
58 
59 import com.android.internal.app.IAppOpsService;
60 import com.android.internal.app.IBatteryStats;
61 import com.android.internal.appwidget.IAppWidgetService;
62 import com.android.internal.os.IDropBoxManagerService;
63 import com.android.internal.view.IInputMethodManager;
64 import java.util.Collections;
65 import java.util.HashMap;
66 import java.util.HashSet;
67 import java.util.Map;
68 import java.util.Set;
69 import org.robolectric.RuntimeEnvironment;
70 import org.robolectric.annotation.Implementation;
71 import org.robolectric.annotation.Implements;
72 import org.robolectric.annotation.Resetter;
73 import org.robolectric.util.ReflectionHelpers;
74 
75 @SuppressWarnings("NewApi")
76 @Implements(value = ServiceManager.class, isInAndroidSdk = false)
77 public class ShadowServiceManager {
78 
79   private static final Map<String, IBinder> SERVICES;
80 
81   private static final Set<String> unavailableServices = new HashSet<>();
82 
83   static {
84     Map<String, IBinder> map = new HashMap<>();
map.put( Context.CLIPBOARD_SERVICE, createBinder(IClipboard.class, "android.content.IClipboard"))85     map.put(
86         Context.CLIPBOARD_SERVICE, createBinder(IClipboard.class, "android.content.IClipboard"));
map.put( Context.WIFI_P2P_SERVICE, createBinder(IWifiP2pManager.class, "android.net.wifi.p2p.IWifiP2pManager"))87     map.put(
88         Context.WIFI_P2P_SERVICE,
89         createBinder(IWifiP2pManager.class, "android.net.wifi.p2p.IWifiP2pManager"));
map.put( Context.ACCOUNT_SERVICE, createBinder(IAccountManager.class, "android.accounts.IAccountManager"))90     map.put(
91         Context.ACCOUNT_SERVICE,
92         createBinder(IAccountManager.class, "android.accounts.IAccountManager"));
map.put( Context.USB_SERVICE, createBinder(IUsbManager.class, "android.hardware.usb.IUsbManager"))93     map.put(
94         Context.USB_SERVICE, createBinder(IUsbManager.class, "android.hardware.usb.IUsbManager"));
map.put( Context.LOCATION_SERVICE, createBinder(ILocationManager.class, "android.location.ILocationManager"))95     map.put(
96         Context.LOCATION_SERVICE,
97         createBinder(ILocationManager.class, "android.location.ILocationManager"));
map.put( Context.INPUT_METHOD_SERVICE, createBinder(IInputMethodManager.class, "com.android.internal.view.IInputMethodManager"))98     map.put(
99         Context.INPUT_METHOD_SERVICE,
100         createBinder(IInputMethodManager.class, "com.android.internal.view.IInputMethodManager"));
map.put(Context.ALARM_SERVICE, createBinder(IAlarmManager.class, "android.app.IAlarmManager"))101     map.put(Context.ALARM_SERVICE, createBinder(IAlarmManager.class, "android.app.IAlarmManager"));
map.put(Context.POWER_SERVICE, createBinder(IPowerManager.class, "android.os.IPowerManager"))102     map.put(Context.POWER_SERVICE, createBinder(IPowerManager.class, "android.os.IPowerManager"));
map.put( BatteryStats.SERVICE_NAME, createBinder(IBatteryStats.class, "com.android.internal.app.IBatteryStats"))103     map.put(
104         BatteryStats.SERVICE_NAME,
105         createBinder(IBatteryStats.class, "com.android.internal.app.IBatteryStats"));
map.put( Context.DROPBOX_SERVICE, createBinder( IDropBoxManagerService.class, "com.android.internal.os.IDropBoxManagerService"))106     map.put(
107         Context.DROPBOX_SERVICE,
108         createBinder(
109             IDropBoxManagerService.class, "com.android.internal.os.IDropBoxManagerService"));
map.put( Context.DEVICE_POLICY_SERVICE, createBinder(IDevicePolicyManager.class, "android.app.admin.IDevicePolicyManager"))110     map.put(
111         Context.DEVICE_POLICY_SERVICE,
112         createBinder(IDevicePolicyManager.class, "android.app.admin.IDevicePolicyManager"));
map.put( Context.CONNECTIVITY_SERVICE, createBinder(IConnectivityManager.class, "android.net.IConnectivityManager"))113     map.put(
114         Context.CONNECTIVITY_SERVICE,
115         createBinder(IConnectivityManager.class, "android.net.IConnectivityManager"));
map.put( Context.WIFI_SERVICE, createBinder(IWifiManager.class, "android.net.wifi.IWifiManager"))116     map.put(
117         Context.WIFI_SERVICE, createBinder(IWifiManager.class, "android.net.wifi.IWifiManager"));
map.put( Context.SEARCH_SERVICE, createBinder(ISearchManager.class, "android.app.ISearchManager"))118     map.put(
119         Context.SEARCH_SERVICE, createBinder(ISearchManager.class, "android.app.ISearchManager"));
map.put( Context.UI_MODE_SERVICE, createBinder(ISearchManager.class, "android.app.IUiModeManager"))120     map.put(
121         Context.UI_MODE_SERVICE, createBinder(ISearchManager.class, "android.app.IUiModeManager"));
map.put( Context.NETWORK_POLICY_SERVICE, createBinder(ISearchManager.class, "android.net.INetworkPolicyManager"))122     map.put(
123         Context.NETWORK_POLICY_SERVICE,
124         createBinder(ISearchManager.class, "android.net.INetworkPolicyManager"));
map.put(Context.INPUT_SERVICE, createBinder(IInputManager.class, "android.net.IInputManager"))125     map.put(Context.INPUT_SERVICE, createBinder(IInputManager.class, "android.net.IInputManager"));
map.put( Context.COUNTRY_DETECTOR, createBinder(ICountryDetector.class, "android.location.ICountryDetector"))126     map.put(
127         Context.COUNTRY_DETECTOR,
128         createBinder(ICountryDetector.class, "android.location.ICountryDetector"));
map.put( Context.NSD_SERVICE, createBinder(INsdManager.class, "android.net.nsd.INsdManagerandroi"))129     map.put(
130         Context.NSD_SERVICE, createBinder(INsdManager.class, "android.net.nsd.INsdManagerandroi"));
map.put( Context.AUDIO_SERVICE, createBinder(IAudioService.class, "android.media.IAudioService"))131     map.put(
132         Context.AUDIO_SERVICE, createBinder(IAudioService.class, "android.media.IAudioService"));
map.put( Context.APPWIDGET_SERVICE, createBinder(IAppWidgetService.class, "com.android.internal.appwidget.IAppWidgetService"))133     map.put(
134         Context.APPWIDGET_SERVICE,
135         createBinder(IAppWidgetService.class, "com.android.internal.appwidget.IAppWidgetService"));
136 
137     if (RuntimeEnvironment.getApiLevel() >= JELLY_BEAN_MR1) {
map.put(Context.USER_SERVICE, createBinder(IUserManager.class, "android.os.IUserManager"))138       map.put(Context.USER_SERVICE, createBinder(IUserManager.class, "android.os.IUserManager"));
139     }
140     if (RuntimeEnvironment.getApiLevel() >= JELLY_BEAN_MR2) {
map.put( Context.APP_OPS_SERVICE, createBinder(IAppOpsService.class, "com.android.internal.app.IAppOpsService"))141       map.put(
142           Context.APP_OPS_SERVICE,
143           createBinder(IAppOpsService.class, "com.android.internal.app.IAppOpsService"));
144     }
145     if (RuntimeEnvironment.getApiLevel() >= KITKAT) {
146       map.put(
147           "batteryproperties",
148           createBinder(
149               IBatteryPropertiesRegistrar.class, "android.os.IBatteryPropertiesRegistrar"));
150     }
151     if (RuntimeEnvironment.getApiLevel() >= LOLLIPOP) {
map.put( Context.RESTRICTIONS_SERVICE, createBinder(IRestrictionsManager.class, "android.content.IRestrictionsManager"))152       map.put(
153           Context.RESTRICTIONS_SERVICE,
154           createBinder(IRestrictionsManager.class, "android.content.IRestrictionsManager"));
map.put( Context.TRUST_SERVICE, createBinder(ITrustManager.class, "android.app.trust.ITrustManager"))155       map.put(
156           Context.TRUST_SERVICE,
157           createBinder(ITrustManager.class, "android.app.trust.ITrustManager"));
map.put( Context.JOB_SCHEDULER_SERVICE, createBinder(IJobScheduler.class, "android.app.job.IJobScheduler"))158       map.put(
159           Context.JOB_SCHEDULER_SERVICE,
160           createBinder(IJobScheduler.class, "android.app.job.IJobScheduler"));
map.put( Context.NETWORK_SCORE_SERVICE, createBinder(INetworkScoreService.class, "android.net.INetworkScoreService"))161       map.put(
162           Context.NETWORK_SCORE_SERVICE,
163           createBinder(INetworkScoreService.class, "android.net.INetworkScoreService"));
map.put( Context.USAGE_STATS_SERVICE, createBinder(IUsageStatsManager.class, "android.app.usage.IUsageStatsManager"))164       map.put(
165           Context.USAGE_STATS_SERVICE,
166           createBinder(IUsageStatsManager.class, "android.app.usage.IUsageStatsManager"));
map.put( Context.MEDIA_ROUTER_SERVICE, createBinder(IMediaRouterService.class, "android.media.IMediaRouterService"))167       map.put(
168           Context.MEDIA_ROUTER_SERVICE,
169           createBinder(IMediaRouterService.class, "android.media.IMediaRouterService"));
map.put( Context.MEDIA_SESSION_SERVICE, createDeepBinder(ISessionManager.class, "android.media.session.ISessionManager"))170       map.put(
171           Context.MEDIA_SESSION_SERVICE,
172           createDeepBinder(ISessionManager.class, "android.media.session.ISessionManager"));
map.put( Context.PERSISTENT_DATA_BLOCK_SERVICE, createBinder(IPersistentDataBlockService.class, "android.service.persistentdata.IPersistentDataBlockService"))173       map.put(
174           Context.PERSISTENT_DATA_BLOCK_SERVICE,
175           createBinder(IPersistentDataBlockService.class,
176                   "android.service.persistentdata.IPersistentDataBlockService"));
177     }
178     if (RuntimeEnvironment.getApiLevel() >= M) {
map.put( Context.FINGERPRINT_SERVICE, createBinder( IFingerprintService.class, "android.hardware.fingerprint.IFingerprintService"))179       map.put(
180           Context.FINGERPRINT_SERVICE,
181           createBinder(
182               IFingerprintService.class, "android.hardware.fingerprint.IFingerprintService"));
183     }
184     if (RuntimeEnvironment.getApiLevel() >= N_MR1) {
map.put( Context.SHORTCUT_SERVICE, createBinder(IShortcutService.class, "android.content.pm.IShortcutService"))185       map.put(
186           Context.SHORTCUT_SERVICE,
187           createBinder(IShortcutService.class, "android.content.pm.IShortcutService"));
188     }
189     if (RuntimeEnvironment.getApiLevel() >= O) {
190       map.put("mount", createBinder(IStorageManager.class, "android.os.storage.IStorageManager"));
191     } else {
192       map.put(
193           "mount",
194           createBinder("android.os.storage.IMountService", "android.os.storage.IMountService"));
195     }
196     if (RuntimeEnvironment.getApiLevel() >= P) {
map.put( Context.SLICE_SERVICE, createBinder(ISliceManager.class, "android.app.slice.SliceManager"))197       map.put(
198           Context.SLICE_SERVICE,
199           createBinder(ISliceManager.class, "android.app.slice.SliceManager"));
map.put( Context.CROSS_PROFILE_APPS_SERVICE, createBinder(ICrossProfileApps.class, "android.content.pm.ICrossProfileApps"))200       map.put(
201           Context.CROSS_PROFILE_APPS_SERVICE,
202           createBinder(ICrossProfileApps.class, "android.content.pm.ICrossProfileApps"));
203     }
204     // BEGIN-INTERNAL
205     if (RuntimeEnvironment.getApiLevel() >= Q) {
map.put(Context.NOTIFICATION_SERVICE, createBinder(INotificationManager.class, "android.app.INotificationManager"))206       map.put(Context.NOTIFICATION_SERVICE,
207           createBinder(INotificationManager.class, "android.app.INotificationManager"));
map.put(Context.COLOR_DISPLAY_SERVICE, createBinder(IColorDisplayManager.class, "android.hardware.display.ColorDisplayManager"))208       map.put(Context.COLOR_DISPLAY_SERVICE, createBinder(IColorDisplayManager.class,
209           "android.hardware.display.ColorDisplayManager"));
210     }
211     if (RuntimeEnvironment.getApiLevel() >= R) {
map.put(Context.TETHERING_SERVICE, createBinder(ITetheringConnector.class, "android.net.ITetheringConnector"))212       map.put(Context.TETHERING_SERVICE,
213               createBinder(ITetheringConnector.class, "android.net.ITetheringConnector"));
map.put(Context.THERMAL_SERVICE, createBinder(IThermalService.class, "android.os.IThermalService"))214       map.put(Context.THERMAL_SERVICE,
215               createBinder(IThermalService.class, "android.os.IThermalService"));
216     }
217     if (RuntimeEnvironment.getApiLevel() >= S) {
218       map.put("permissionmgr",
219               createBinder(IPermissionManager.class, "android.permission.IPermissionManager"));
map.put(Context.VPN_MANAGEMENT_SERVICE, createBinder(IVpnManager.class, "android.net.IVpnManager"))220       map.put(Context.VPN_MANAGEMENT_SERVICE,
221               createBinder(IVpnManager.class, "android.net.IVpnManager"));
222     }
223     // END-INTERNAL
224     SERVICES = Collections.unmodifiableMap(map);
225   }
226 
227   /**
228    * Returns the binder associated with the given system service. If the given service is set to
229    * unavailable in {@link #setServiceAvailability}, {@code null} will be returned.
230    */
231   @Implementation
getService(String name)232   protected static IBinder getService(String name) {
233     if (unavailableServices.contains(name)) {
234       return null;
235     }
236     return SERVICES.get(name);
237   }
238 
createBinder(String className, String descriptor)239   private static Binder createBinder(String className, String descriptor) {
240     Class<IInterface> clazz;
241     try {
242       clazz = (Class<IInterface>) Class.forName(className);
243     } catch (ClassNotFoundException e) {
244       throw new RuntimeException(e);
245     }
246     Binder binder = new Binder();
247     binder.attachInterface(ReflectionHelpers.createNullProxy(clazz), descriptor);
248     return binder;
249   }
250 
createBinder(Class<? extends IInterface> clazz, String descriptor)251   private static Binder createBinder(Class<? extends IInterface> clazz, String descriptor) {
252     Binder binder = new Binder();
253     binder.attachInterface(ReflectionHelpers.createNullProxy(clazz), descriptor);
254     return binder;
255   }
256 
createDeepBinder(Class<? extends IInterface> clazz, String descriptor)257   private static Binder createDeepBinder(Class<? extends IInterface> clazz, String descriptor) {
258     Binder binder = new Binder();
259     binder.attachInterface(ReflectionHelpers.createDeepProxy(clazz), descriptor);
260     return binder;
261   }
262 
263   @Implementation
addService(String name, IBinder service)264   protected static void addService(String name, IBinder service) {}
265 
266   @Implementation
checkService(String name)267   protected static IBinder checkService(String name) {
268     return null;
269   }
270 
271   @Implementation
listServices()272   protected static String[] listServices() throws RemoteException {
273     return null;
274   }
275 
276   @Implementation
initServiceCache(Map<String, IBinder> cache)277   protected static void initServiceCache(Map<String, IBinder> cache) {}
278 
279   /**
280    * Sets the availability of the given system service. If the service is set as unavailable,
281    * subsequent calls to {@link Context#getSystemService} for that service will return {@code null}.
282    */
setServiceAvailability(String service, boolean available)283   public static void setServiceAvailability(String service, boolean available) {
284     if (available) {
285       unavailableServices.remove(service);
286     } else {
287       unavailableServices.add(service);
288     }
289   }
290 
291   @Resetter
reset()292   public static void reset() {
293     unavailableServices.clear();
294   }
295 }
296