Clean up, de-dup, and speed up ContextImpl getSystemService()
Bug: 3191436
Change-Id: I343adc016e02d0414b2d48a14e5e62a5cccb7899
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 129c29d..dda3107 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -106,9 +106,6 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.WeakHashMap;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutorService;
class ReceiverRestrictedContext extends ContextWrapper {
ReceiverRestrictedContext(Context base) {
@@ -149,18 +146,9 @@
private final static String TAG = "ApplicationContext";
private final static boolean DEBUG = false;
- private static final Object sSync = new Object();
- private static AlarmManager sAlarmManager;
- private static PowerManager sPowerManager;
- private static ConnectivityManager sConnectivityManager;
- private static ThrottleManager sThrottleManager;
- private static WifiManager sWifiManager;
- private static LocationManager sLocationManager;
- private static CountryDetector sCountryDetector;
private static final HashMap<String, SharedPreferencesImpl> sSharedPrefs =
new HashMap<String, SharedPreferencesImpl>();
- private AudioManager mAudioManager;
/*package*/ LoadedApk mPackageInfo;
private Resources mResources;
/*package*/ ActivityThread mMainThread;
@@ -170,24 +158,8 @@
private int mThemeResource = 0;
private Resources.Theme mTheme = null;
private PackageManager mPackageManager;
- private NotificationManager mNotificationManager = null;
- private ActivityManager mActivityManager = null;
- private WallpaperManager mWallpaperManager = null;
private Context mReceiverRestrictedContext = null;
- private SearchManager mSearchManager = null;
- private SensorManager mSensorManager = null;
- private StorageManager mStorageManager = null;
- private Vibrator mVibrator = null;
- private LayoutInflater mLayoutInflater = null;
- private StatusBarManager mStatusBarManager = null;
- private TelephonyManager mTelephonyManager = null;
- private ClipboardManager mClipboardManager = null;
private boolean mRestricted;
- private AccountManager mAccountManager; // protected by mSync
- private DropBoxManager mDropBoxManager = null;
- private DevicePolicyManager mDevicePolicyManager = null;
- private UiModeManager mUiModeManager = null;
- private DownloadManager mDownloadManager = null;
private final Object mSync = new Object();
@@ -200,6 +172,266 @@
private static final String[] EMPTY_FILE_LIST = {};
+ /**
+ * Override this class when the system service constructor needs a
+ * ContextImpl. Else, use StaticServiceFetcher below.
+ */
+ /*package*/ static class ServiceFetcher {
+ int mContextCacheIndex = -1;
+
+ /**
+ * Main entrypoint; only override if you don't need caching.
+ */
+ public Object getService(ContextImpl ctx) {
+ ArrayList<Object> cache = ctx.mServiceCache;
+ Object service;
+ synchronized (cache) {
+ if (cache.size() == 0) {
+ // Initialize the cache vector on first access.
+ // At this point sNextPerContextServiceCacheIndex
+ // is the number of potential services that are
+ // cached per-Context.
+ for (int i = 0; i < sNextPerContextServiceCacheIndex; i++) {
+ cache.add(null);
+ }
+ } else {
+ service = cache.get(mContextCacheIndex);
+ if (service != null) {
+ return service;
+ }
+ }
+ service = createService(ctx);
+ cache.set(mContextCacheIndex, service);
+ return service;
+ }
+ }
+
+ /**
+ * Override this to create a new per-Context instance of the
+ * service. getService() will handle locking and caching.
+ */
+ public Object createService(ContextImpl ctx) {
+ throw new RuntimeException("Not implemented");
+ }
+ }
+
+ /**
+ * Override this class for services to be cached process-wide.
+ */
+ abstract static class StaticServiceFetcher extends ServiceFetcher {
+ private Object mCachedInstance;
+
+ @Override
+ public final Object getService(ContextImpl unused) {
+ synchronized (StaticServiceFetcher.this) {
+ Object service = mCachedInstance;
+ if (service != null) {
+ return service;
+ }
+ return mCachedInstance = createStaticService();
+ }
+ }
+
+ public abstract Object createStaticService();
+ }
+
+ private static final HashMap<String, ServiceFetcher> SYSTEM_SERVICE_MAP =
+ new HashMap<String, ServiceFetcher>();
+
+ private static int sNextPerContextServiceCacheIndex = 0;
+ private static void registerService(String serviceName, ServiceFetcher fetcher) {
+ if (!(fetcher instanceof StaticServiceFetcher)) {
+ fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;
+ }
+ SYSTEM_SERVICE_MAP.put(serviceName, fetcher);
+ }
+
+ // This one's defined separately and given a variable name so it
+ // can be re-used by getWallpaperManager(), avoiding a HashMap
+ // lookup.
+ private static ServiceFetcher WALLPAPER_FETCHER = new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ return new WallpaperManager(ctx.getOuterContext(),
+ ctx.mMainThread.getHandler());
+ }};
+
+ static {
+ registerService(ACCESSIBILITY_SERVICE, new ServiceFetcher() {
+ public Object getService(ContextImpl ctx) {
+ return AccessibilityManager.getInstance(ctx);
+ }});
+
+ registerService(ACCOUNT_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(ACCOUNT_SERVICE);
+ IAccountManager service = IAccountManager.Stub.asInterface(b);
+ return new AccountManager(ctx, service);
+ }});
+
+ registerService(ACTIVITY_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ return new ActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler());
+ }});
+
+ registerService(ALARM_SERVICE, new StaticServiceFetcher() {
+ public Object createStaticService() {
+ IBinder b = ServiceManager.getService(ALARM_SERVICE);
+ IAlarmManager service = IAlarmManager.Stub.asInterface(b);
+ return new AlarmManager(service);
+ }});
+
+ registerService(AUDIO_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ return new AudioManager(ctx);
+ }});
+
+ registerService(CLIPBOARD_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ return new ClipboardManager(ctx.getOuterContext(),
+ ctx.mMainThread.getHandler());
+ }});
+
+ registerService(CONNECTIVITY_SERVICE, new StaticServiceFetcher() {
+ public Object createStaticService() {
+ IBinder b = ServiceManager.getService(CONNECTIVITY_SERVICE);
+ return new ConnectivityManager(IConnectivityManager.Stub.asInterface(b));
+ }});
+
+ registerService(COUNTRY_DETECTOR, new StaticServiceFetcher() {
+ public Object createStaticService() {
+ IBinder b = ServiceManager.getService(COUNTRY_DETECTOR);
+ return new CountryDetector(ICountryDetector.Stub.asInterface(b));
+ }});
+
+ registerService(DEVICE_POLICY_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ return DevicePolicyManager.create(ctx, ctx.mMainThread.getHandler());
+ }});
+
+ registerService(DOWNLOAD_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ return new DownloadManager(ctx.getContentResolver(), ctx.getPackageName());
+ }});
+
+ registerService(DROPBOX_SERVICE, new StaticServiceFetcher() {
+ public Object createStaticService() {
+ return createDropBoxManager();
+ }});
+
+ registerService(INPUT_METHOD_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ return InputMethodManager.getInstance(ctx);
+ }});
+
+ registerService(KEYGUARD_SERVICE, new ServiceFetcher() {
+ public Object getService(ContextImpl ctx) {
+ // TODO: why isn't this caching it? It wasn't
+ // before, so I'm preserving the old behavior and
+ // using getService(), instead of createService()
+ // which would do the caching.
+ return new KeyguardManager();
+ }});
+
+ registerService(LAYOUT_INFLATER_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ return PolicyManager.makeNewLayoutInflater(ctx.getOuterContext());
+ }});
+
+ registerService(LOCATION_SERVICE, new StaticServiceFetcher() {
+ public Object createStaticService() {
+ IBinder b = ServiceManager.getService(LOCATION_SERVICE);
+ return new LocationManager(ILocationManager.Stub.asInterface(b));
+ }});
+
+ registerService(NOTIFICATION_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ final Context outerContext = ctx.getOuterContext();
+ return new NotificationManager(
+ new ContextThemeWrapper(outerContext,
+ outerContext.getApplicationInfo().targetSdkVersion >=
+ Build.VERSION_CODES.HONEYCOMB
+ ? com.android.internal.R.style.Theme_Holo_Dialog
+ : com.android.internal.R.style.Theme_Dialog),
+ ctx.mMainThread.getHandler());
+ }});
+
+ // Note: this was previously cached in a static variable, but
+ // constructed using mMainThread.getHandler(), so converting
+ // it to be a regular Context-cached service...
+ registerService(POWER_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(POWER_SERVICE);
+ IPowerManager service = IPowerManager.Stub.asInterface(b);
+ return new PowerManager(service, ctx.mMainThread.getHandler());
+ }});
+
+ registerService(SEARCH_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ return new SearchManager(ctx.getOuterContext(),
+ ctx.mMainThread.getHandler());
+ }});
+
+ registerService(SENSOR_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ return new SensorManager(ctx.mMainThread.getHandler().getLooper());
+ }});
+
+ registerService(STATUS_BAR_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ return new StatusBarManager(ctx.getOuterContext());
+ }});
+
+ registerService(STORAGE_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ try {
+ return new StorageManager(ctx.mMainThread.getHandler().getLooper());
+ } catch (RemoteException rex) {
+ Log.e(TAG, "Failed to create StorageManager", rex);
+ return null;
+ }
+ }});
+
+ registerService(TELEPHONY_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ return new TelephonyManager(ctx.getOuterContext());
+ }});
+
+ registerService(THROTTLE_SERVICE, new StaticServiceFetcher() {
+ public Object createStaticService() {
+ IBinder b = ServiceManager.getService(THROTTLE_SERVICE);
+ return new ThrottleManager(IThrottleManager.Stub.asInterface(b));
+ }});
+
+ registerService(UI_MODE_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ return new UiModeManager();
+ }});
+
+ registerService(VIBRATOR_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ return new Vibrator();
+ }});
+
+ registerService(WALLPAPER_SERVICE, WALLPAPER_FETCHER);
+
+ registerService(WIFI_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(WIFI_SERVICE);
+ IWifiManager service = IWifiManager.Stub.asInterface(b);
+ return new WifiManager(service, ctx.mMainThread.getHandler());
+ }});
+
+ registerService(WINDOW_SERVICE, new ServiceFetcher() {
+ public Object getService(ContextImpl ctx) {
+ return WindowManagerImpl.getDefault();
+ }});
+ }
+
+ // The system service cache for the system services that are
+ // cached per-ContextImpl. Package-scoped to avoid accessor
+ // methods.
+ final ArrayList<Object> mServiceCache = new ArrayList<Object>();
+
@Override
public AssetManager getAssets() {
return mResources.getAssets();
@@ -895,273 +1127,12 @@
@Override
public Object getSystemService(String name) {
- if (WINDOW_SERVICE.equals(name)) {
- return WindowManagerImpl.getDefault();
- } else if (LAYOUT_INFLATER_SERVICE.equals(name)) {
- synchronized (mSync) {
- LayoutInflater inflater = mLayoutInflater;
- if (inflater != null) {
- return inflater;
- }
- mLayoutInflater = inflater =
- PolicyManager.makeNewLayoutInflater(getOuterContext());
- return inflater;
- }
- } else if (ACTIVITY_SERVICE.equals(name)) {
- return getActivityManager();
- } else if (INPUT_METHOD_SERVICE.equals(name)) {
- return InputMethodManager.getInstance(this);
- } else if (ALARM_SERVICE.equals(name)) {
- return getAlarmManager();
- } else if (ACCOUNT_SERVICE.equals(name)) {
- return getAccountManager();
- } else if (POWER_SERVICE.equals(name)) {
- return getPowerManager();
- } else if (CONNECTIVITY_SERVICE.equals(name)) {
- return getConnectivityManager();
- } else if (THROTTLE_SERVICE.equals(name)) {
- return getThrottleManager();
- } else if (WIFI_SERVICE.equals(name)) {
- return getWifiManager();
- } else if (NOTIFICATION_SERVICE.equals(name)) {
- return getNotificationManager();
- } else if (KEYGUARD_SERVICE.equals(name)) {
- return new KeyguardManager();
- } else if (ACCESSIBILITY_SERVICE.equals(name)) {
- return AccessibilityManager.getInstance(this);
- } else if (LOCATION_SERVICE.equals(name)) {
- return getLocationManager();
- } else if (COUNTRY_DETECTOR.equals(name)) {
- return getCountryDetector();
- } else if (SEARCH_SERVICE.equals(name)) {
- return getSearchManager();
- } else if (SENSOR_SERVICE.equals(name)) {
- return getSensorManager();
- } else if (STORAGE_SERVICE.equals(name)) {
- return getStorageManager();
- } else if (VIBRATOR_SERVICE.equals(name)) {
- return getVibrator();
- } else if (STATUS_BAR_SERVICE.equals(name)) {
- synchronized (mSync) {
- if (mStatusBarManager == null) {
- mStatusBarManager = new StatusBarManager(getOuterContext());
- }
- return mStatusBarManager;
- }
- } else if (AUDIO_SERVICE.equals(name)) {
- return getAudioManager();
- } else if (TELEPHONY_SERVICE.equals(name)) {
- return getTelephonyManager();
- } else if (CLIPBOARD_SERVICE.equals(name)) {
- return getClipboardManager();
- } else if (WALLPAPER_SERVICE.equals(name)) {
- return getWallpaperManager();
- } else if (DROPBOX_SERVICE.equals(name)) {
- return getDropBoxManager();
- } else if (DEVICE_POLICY_SERVICE.equals(name)) {
- return getDevicePolicyManager();
- } else if (UI_MODE_SERVICE.equals(name)) {
- return getUiModeManager();
- } else if (DOWNLOAD_SERVICE.equals(name)) {
- return getDownloadManager();
- }
-
- return null;
- }
-
- private AccountManager getAccountManager() {
- synchronized (mSync) {
- if (mAccountManager == null) {
- IBinder b = ServiceManager.getService(ACCOUNT_SERVICE);
- IAccountManager service = IAccountManager.Stub.asInterface(b);
- mAccountManager = new AccountManager(this, service);
- }
- return mAccountManager;
- }
- }
-
- private ActivityManager getActivityManager() {
- synchronized (mSync) {
- if (mActivityManager == null) {
- mActivityManager = new ActivityManager(getOuterContext(),
- mMainThread.getHandler());
- }
- }
- return mActivityManager;
- }
-
- private AlarmManager getAlarmManager() {
- synchronized (sSync) {
- if (sAlarmManager == null) {
- IBinder b = ServiceManager.getService(ALARM_SERVICE);
- IAlarmManager service = IAlarmManager.Stub.asInterface(b);
- sAlarmManager = new AlarmManager(service);
- }
- }
- return sAlarmManager;
- }
-
- private PowerManager getPowerManager() {
- synchronized (sSync) {
- if (sPowerManager == null) {
- IBinder b = ServiceManager.getService(POWER_SERVICE);
- IPowerManager service = IPowerManager.Stub.asInterface(b);
- sPowerManager = new PowerManager(service, mMainThread.getHandler());
- }
- }
- return sPowerManager;
- }
-
- private ConnectivityManager getConnectivityManager()
- {
- synchronized (sSync) {
- if (sConnectivityManager == null) {
- IBinder b = ServiceManager.getService(CONNECTIVITY_SERVICE);
- IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
- sConnectivityManager = new ConnectivityManager(service);
- }
- }
- return sConnectivityManager;
- }
-
- private ThrottleManager getThrottleManager()
- {
- synchronized (sSync) {
- if (sThrottleManager == null) {
- IBinder b = ServiceManager.getService(THROTTLE_SERVICE);
- IThrottleManager service = IThrottleManager.Stub.asInterface(b);
- sThrottleManager = new ThrottleManager(service);
- }
- }
- return sThrottleManager;
- }
-
- private WifiManager getWifiManager()
- {
- synchronized (sSync) {
- if (sWifiManager == null) {
- IBinder b = ServiceManager.getService(WIFI_SERVICE);
- IWifiManager service = IWifiManager.Stub.asInterface(b);
- sWifiManager = new WifiManager(service, mMainThread.getHandler());
- }
- }
- return sWifiManager;
- }
-
- private NotificationManager getNotificationManager() {
- synchronized (mSync) {
- if (mNotificationManager == null) {
- final Context outerContext = getOuterContext();
- mNotificationManager = new NotificationManager(
- new ContextThemeWrapper(outerContext,
- outerContext.getApplicationInfo().targetSdkVersion >=
- Build.VERSION_CODES.HONEYCOMB
- ? com.android.internal.R.style.Theme_Holo_Dialog
- : com.android.internal.R.style.Theme_Dialog),
- mMainThread.getHandler());
- }
- }
- return mNotificationManager;
+ ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
+ return fetcher == null ? null : fetcher.getService(this);
}
private WallpaperManager getWallpaperManager() {
- synchronized (mSync) {
- if (mWallpaperManager == null) {
- mWallpaperManager = new WallpaperManager(getOuterContext(),
- mMainThread.getHandler());
- }
- }
- return mWallpaperManager;
- }
-
- private TelephonyManager getTelephonyManager() {
- synchronized (mSync) {
- if (mTelephonyManager == null) {
- mTelephonyManager = new TelephonyManager(getOuterContext());
- }
- }
- return mTelephonyManager;
- }
-
- private ClipboardManager getClipboardManager() {
- synchronized (mSync) {
- if (mClipboardManager == null) {
- mClipboardManager = new ClipboardManager(getOuterContext(),
- mMainThread.getHandler());
- }
- }
- return mClipboardManager;
- }
-
- private LocationManager getLocationManager() {
- synchronized (sSync) {
- if (sLocationManager == null) {
- IBinder b = ServiceManager.getService(LOCATION_SERVICE);
- ILocationManager service = ILocationManager.Stub.asInterface(b);
- sLocationManager = new LocationManager(service);
- }
- }
- return sLocationManager;
- }
-
- private CountryDetector getCountryDetector() {
- synchronized (sSync) {
- if (sCountryDetector == null) {
- IBinder b = ServiceManager.getService(COUNTRY_DETECTOR);
- ICountryDetector service = ICountryDetector.Stub.asInterface(b);
- sCountryDetector = new CountryDetector(service);
- }
- }
- return sCountryDetector;
- }
-
- private SearchManager getSearchManager() {
- synchronized (mSync) {
- if (mSearchManager == null) {
- mSearchManager = new SearchManager(getOuterContext(), mMainThread.getHandler());
- }
- }
- return mSearchManager;
- }
-
- private SensorManager getSensorManager() {
- synchronized (mSync) {
- if (mSensorManager == null) {
- mSensorManager = new SensorManager(mMainThread.getHandler().getLooper());
- }
- }
- return mSensorManager;
- }
-
- private StorageManager getStorageManager() {
- synchronized (mSync) {
- if (mStorageManager == null) {
- try {
- mStorageManager = new StorageManager(mMainThread.getHandler().getLooper());
- } catch (RemoteException rex) {
- Log.e(TAG, "Failed to create StorageManager", rex);
- mStorageManager = null;
- }
- }
- }
- return mStorageManager;
- }
-
- private Vibrator getVibrator() {
- synchronized (mSync) {
- if (mVibrator == null) {
- mVibrator = new Vibrator();
- }
- }
- return mVibrator;
- }
-
- private AudioManager getAudioManager()
- {
- if (mAudioManager == null) {
- mAudioManager = new AudioManager(this);
- }
- return mAudioManager;
+ return (WallpaperManager) WALLPAPER_FETCHER.getService(this);
}
/* package */ static DropBoxManager createDropBoxManager() {
@@ -1177,43 +1148,6 @@
return new DropBoxManager(service);
}
- private DropBoxManager getDropBoxManager() {
- synchronized (mSync) {
- if (mDropBoxManager == null) {
- mDropBoxManager = createDropBoxManager();
- }
- }
- return mDropBoxManager;
- }
-
- private DevicePolicyManager getDevicePolicyManager() {
- synchronized (mSync) {
- if (mDevicePolicyManager == null) {
- mDevicePolicyManager = DevicePolicyManager.create(this,
- mMainThread.getHandler());
- }
- }
- return mDevicePolicyManager;
- }
-
- private UiModeManager getUiModeManager() {
- synchronized (mSync) {
- if (mUiModeManager == null) {
- mUiModeManager = new UiModeManager();
- }
- }
- return mUiModeManager;
- }
-
- private DownloadManager getDownloadManager() {
- synchronized (mSync) {
- if (mDownloadManager == null) {
- mDownloadManager = new DownloadManager(getContentResolver(), getPackageName());
- }
- }
- return mDownloadManager;
- }
-
@Override
public int checkPermission(String permission, int pid, int uid) {
if (permission == null) {