OSDN Git Service

Initializing LauncherAppState only on the main thread
authorSunny Goyal <sunnygoyal@google.com>
Wed, 1 Feb 2017 20:52:54 +0000 (12:52 -0800)
committerSunny Goyal <sunnygoyal@google.com>
Tue, 14 Feb 2017 01:36:18 +0000 (17:36 -0800)
Bug: 33032833
Change-Id: I7992a5358142dde80aeaf8c6b7a6c7bfef2c8a00

src/com/android/launcher3/LauncherAppState.java
src/com/android/launcher3/LauncherProvider.java

index 4dc5a97..55c3703 100644 (file)
 
 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<LauncherProvider> 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<LauncherAppState>() {
+                        @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();
+        }
+    }
 }
index 6266fae..e71ef2c 100644 (file)
@@ -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;
     }