From fdbef27759bdd5ccaca6a0e70fbdf008c0053981 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Wed, 1 Feb 2017 12:52:54 -0800 Subject: Initializing LauncherAppState only on the main thread Bug: 33032833 Change-Id: I7992a5358142dde80aeaf8c6b7a6c7bfef2c8a00 --- src/com/android/launcher3/LauncherAppState.java | 99 ++++++++++++++----------- src/com/android/launcher3/LauncherProvider.java | 6 +- 2 files changed, 59 insertions(+), 46 deletions(-) (limited to 'src') diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java index 4dc5a9727..55c370387 100644 --- a/src/com/android/launcher3/LauncherAppState.java +++ b/src/com/android/launcher3/LauncherAppState.java @@ -16,9 +16,11 @@ package com.android.launcher3; +import android.content.ContentProviderClient; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.os.Looper; import android.util.Log; import com.android.launcher3.compat.LauncherAppsCompat; @@ -26,31 +28,43 @@ import com.android.launcher3.compat.PackageInstallerCompat; import com.android.launcher3.compat.UserManagerCompat; import com.android.launcher3.config.ProviderConfig; import com.android.launcher3.dynamicui.ExtractionUtils; -import com.android.launcher3.logging.FileLog; import com.android.launcher3.util.ConfigMonitor; +import com.android.launcher3.util.Preconditions; import com.android.launcher3.util.TestingUtils; -import com.android.launcher3.util.Thunk; -import java.lang.ref.WeakReference; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; public class LauncherAppState { public static final boolean PROFILE_STARTUP = ProviderConfig.IS_DOGFOOD_BUILD; - @Thunk final LauncherModel mModel; + // We do not need any synchronization for this variable as its only written on UI thread. + private static LauncherAppState INSTANCE; + + private final Context mContext; + private final LauncherModel mModel; private final IconCache mIconCache; private final WidgetPreviewLoader mWidgetCache; + private final InvariantDeviceProfile mInvariantDeviceProfile; - private static WeakReference sLauncherProvider; - private static Context sContext; - - private static LauncherAppState INSTANCE; - private InvariantDeviceProfile mInvariantDeviceProfile; - - public static LauncherAppState getInstance(Context context) { + public static LauncherAppState getInstance(final Context context) { if (INSTANCE == null) { - INSTANCE = new LauncherAppState(); + if (Looper.myLooper() == Looper.getMainLooper()) { + INSTANCE = new LauncherAppState(context.getApplicationContext()); + } else { + try { + return new MainThreadExecutor().submit(new Callable() { + @Override + public LauncherAppState call() throws Exception { + return LauncherAppState.getInstance(context); + } + }).get(); + } catch (InterruptedException|ExecutionException e) { + throw new RuntimeException(e); + } + } } return INSTANCE; } @@ -60,42 +74,30 @@ public class LauncherAppState { } public Context getContext() { - return sContext; + return mContext; } - static void setLauncherProvider(LauncherProvider provider) { - if (sLauncherProvider != null) { - Log.w(Launcher.TAG, "setLauncherProvider called twice! old=" + - sLauncherProvider.get() + " new=" + provider); + private LauncherAppState(Context context) { + if (getLocalProvider(context) == null) { + throw new RuntimeException( + "Initializing LauncherAppState in the absence of LauncherProvider"); } - sLauncherProvider = new WeakReference<>(provider); - - // The content provider exists for the entire duration of the launcher main process and - // is the first component to get created. Initializing application context here ensures - // that LauncherAppState always exists in the main process. - sContext = provider.getContext().getApplicationContext(); - FileLog.setDir(sContext.getFilesDir()); - } - - private LauncherAppState() { - if (sContext == null) { - throw new IllegalStateException("LauncherAppState initiated before app context set"); - } - Log.v(Launcher.TAG, "LauncherAppState initiated"); + Preconditions.assertUIThread(); + mContext = context; if (TestingUtils.MEMORY_DUMP_ENABLED) { - TestingUtils.startTrackingMemory(sContext); + TestingUtils.startTrackingMemory(mContext); } - mInvariantDeviceProfile = new InvariantDeviceProfile(sContext); - mIconCache = new IconCache(sContext, mInvariantDeviceProfile); - mWidgetCache = new WidgetPreviewLoader(sContext, mIconCache); + mInvariantDeviceProfile = new InvariantDeviceProfile(mContext); + mIconCache = new IconCache(mContext, mInvariantDeviceProfile); + mWidgetCache = new WidgetPreviewLoader(mContext, mIconCache); mModel = new LauncherModel(this, mIconCache, - Utilities.getOverrideObject(AppFilter.class, sContext, R.string.app_filter_class)); + Utilities.getOverrideObject(AppFilter.class, mContext, R.string.app_filter_class)); - LauncherAppsCompat.getInstance(sContext).addOnAppsChangedCallback(mModel); + LauncherAppsCompat.getInstance(mContext).addOnAppsChangedCallback(mModel); // Register intent receivers IntentFilter filter = new IntentFilter(); @@ -112,21 +114,21 @@ public class LauncherAppState { filter.addAction(Intent.ACTION_WALLPAPER_CHANGED); } - sContext.registerReceiver(mModel, filter); - UserManagerCompat.getInstance(sContext).enableAndResetCache(); - new ConfigMonitor(sContext).register(); + mContext.registerReceiver(mModel, filter); + UserManagerCompat.getInstance(mContext).enableAndResetCache(); + new ConfigMonitor(mContext).register(); - ExtractionUtils.startColorExtractionServiceIfNecessary(sContext); + ExtractionUtils.startColorExtractionServiceIfNecessary(mContext); } /** * Call from Application.onTerminate(), which is not guaranteed to ever be called. */ public void onTerminate() { - sContext.unregisterReceiver(mModel); - final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(sContext); + mContext.unregisterReceiver(mModel); + final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(mContext); launcherApps.removeOnAppsChangedCallback(mModel); - PackageInstallerCompat.getInstance(sContext).onStop(); + PackageInstallerCompat.getInstance(mContext).onStop(); } /** @@ -139,7 +141,7 @@ public class LauncherAppState { } LauncherModel setLauncher(Launcher launcher) { - sLauncherProvider.get().setLauncherProviderChangeListener(launcher); + getLocalProvider(mContext).setLauncherProviderChangeListener(launcher); mModel.initialize(launcher); return mModel; } @@ -166,4 +168,11 @@ public class LauncherAppState { public static InvariantDeviceProfile getIDP(Context context) { return LauncherAppState.getInstance(context).getInvariantDeviceProfile(); } + + private static LauncherProvider getLocalProvider(Context context) { + try (ContentProviderClient cl = context.getContentResolver() + .acquireContentProviderClient(LauncherProvider.AUTHORITY)) { + return (LauncherProvider) cl.getLocalContentProvider(); + } + } } diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java index 6266fae8f..e71ef2ce5 100644 --- a/src/com/android/launcher3/LauncherProvider.java +++ b/src/com/android/launcher3/LauncherProvider.java @@ -55,6 +55,7 @@ import com.android.launcher3.compat.UserManagerCompat; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.config.ProviderConfig; import com.android.launcher3.dynamicui.ExtractionUtils; +import com.android.launcher3.logging.FileLog; import com.android.launcher3.provider.LauncherDbUtils; import com.android.launcher3.provider.RestoreDbTask; import com.android.launcher3.util.ManagedProfileHeuristic; @@ -91,7 +92,10 @@ public class LauncherProvider extends ContentProvider { } mListenerHandler = new Handler(mListenerWrapper); - LauncherAppState.setLauncherProvider(this); + // The content provider exists for the entire duration of the launcher main process and + // is the first component to get created. Initializing FileLog here ensures that it's + // always available in the main process. + FileLog.setDir(getContext().getApplicationContext().getFilesDir()); return true; } -- cgit v1.2.3