Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 10305208 authored by Makoto Onuki's avatar Makoto Onuki
Browse files

Cache the default launcher.

Originally we always checked with PM for the default launcher,
which would take ~2ms.

Now we cache the result, and clears the cache when (any) preferred
activities change.

Bug 30126557

Change-Id: Iceef288cd372c8bb9b119aa493e5173d894f2302
parent 83fa7a82
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -2218,6 +2218,22 @@ public class Intent implements Parcelable, Cloneable {
    public static final String ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE =
        "android.intent.action.EXTERNAL_APPLICATIONS_UNAVAILABLE";

    /**
     * Broadcast Action: preferred activities have changed *explicitly*.
     *
     * <p>Note there are cases where a preferred activity is invalidated *implicitly*, e.g.
     * when an app is installed or uninstalled, but in such cases this broadcast will *not*
     * be sent.
     *
     * {@link #EXTRA_USER_HANDLE} contains the user ID in question.
     *
     * @hide
     */
    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    public static final String ACTION_PREFERRED_ACTIVITY_CHANGED =
            "android.intent.action.ACTION_PREFERRED_ACTIVITY_CHANGED";


    /**
     * Broadcast Action:  The current system wallpaper has changed.  See
     * {@link android.app.WallpaperManager} for retrieving the new wallpaper.
+1 −0
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@
    <protected-broadcast android:name="android.intent.action.PACKAGE_VERIFIED" />
    <protected-broadcast android:name="android.intent.action.PACKAGES_SUSPENDED" />
    <protected-broadcast android:name="android.intent.action.PACKAGES_UNSUSPENDED" />
    <protected-broadcast android:name="android.intent.action.ACTION_PREFERRED_ACTIVITY_CHANGED" />
    <protected-broadcast android:name="android.intent.action.UID_REMOVED" />
    <protected-broadcast android:name="android.intent.action.QUERY_PACKAGE_RESTART" />
    <protected-broadcast android:name="android.intent.action.CONFIGURATION_CHANGED" />
+24 −0
Original line number Diff line number Diff line
@@ -16886,9 +16886,28 @@ public class PackageManagerService extends IPackageManager.Stub {
            filter.dump(new LogPrinter(Log.INFO, TAG), "  ");
            pir.addFilter(new PreferredActivity(filter, match, set, activity, always));
            scheduleWritePackageRestrictionsLocked(userId);
            postPreferredActivityChangedBroadcast(userId);
        }
    }
    private void postPreferredActivityChangedBroadcast(int userId) {
        mHandler.post(() -> {
            final IActivityManager am = ActivityManagerNative.getDefault();
            if (am == null) {
                return;
            }
            final Intent intent = new Intent(Intent.ACTION_PREFERRED_ACTIVITY_CHANGED);
            intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
            try {
                am.broadcastIntent(null, intent, null, null,
                        0, null, null, null, android.app.AppOpsManager.OP_NONE,
                        null, false, false, userId);
            } catch (RemoteException e) {
            }
        });
    }
    @Override
    public void replacePreferredActivity(IntentFilter filter, int match,
            ComponentName[] set, ComponentName activity, int userId) {
@@ -17040,6 +17059,9 @@ public class PackageManagerService extends IPackageManager.Stub {
                changed = true;
            }
        }
        if (changed) {
            postPreferredActivityChangedBroadcast(userId);
        }
        return changed;
    }
@@ -17153,6 +17175,7 @@ public class PackageManagerService extends IPackageManager.Stub {
            mSettings.editPersistentPreferredActivitiesLPw(userId).addFilter(
                    new PersistentPreferredActivity(filter, activity));
            scheduleWritePackageRestrictionsLocked(userId);
            postPreferredActivityChangedBroadcast(userId);
        }
    }
@@ -17195,6 +17218,7 @@ public class PackageManagerService extends IPackageManager.Stub {
            if (changed) {
                scheduleWritePackageRestrictionsLocked(userId);
                postPreferredActivityChangedBroadcast(userId);
            }
        }
    }
+40 −16
Original line number Diff line number Diff line
@@ -385,6 +385,12 @@ public class ShortcutService extends IShortcutService.Stub {
        mContext.registerReceiverAsUser(mPackageMonitor, UserHandle.ALL,
                packageFilter, null, mHandler);

        final IntentFilter preferedActivityFilter = new IntentFilter();
        preferedActivityFilter.addAction(Intent.ACTION_PREFERRED_ACTIVITY_CHANGED);
        preferedActivityFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
        mContext.registerReceiverAsUser(mPackageMonitor, UserHandle.ALL,
                preferedActivityFilter, null, mHandler);

        final IntentFilter localeFilter = new IntentFilter();
        localeFilter.addAction(Intent.ACTION_LOCALE_CHANGED);
        localeFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
@@ -1923,7 +1929,12 @@ public class ShortcutService extends IShortcutService.Stub {

    // We override this method in unit tests to do a simpler check.
    boolean hasShortcutHostPermission(@NonNull String callingPackage, int userId) {
        final long start = injectElapsedRealtime();
        try {
            return hasShortcutHostPermissionInner(callingPackage, userId);
        } finally {
            logDurationStat(Stats.LAUNCHER_PERMISSION_CHECK, start);
        }
    }

    // This method is extracted so we can directly call this method from unit tests,
@@ -1931,15 +1942,22 @@ public class ShortcutService extends IShortcutService.Stub {
    @VisibleForTesting
    boolean hasShortcutHostPermissionInner(@NonNull String callingPackage, int userId) {
        synchronized (mLock) {
            final long start = injectElapsedRealtime();

            final ShortcutUser user = getUserShortcutsLocked(userId);

            // Always trust the in-memory cache.
            final ComponentName cached = user.getCachedLauncher();
            if (cached != null) {
                if (cached.getPackageName().equals(callingPackage)) {
                    return true;
                }
            }
            // If the cached one doesn't match, then go ahead

            final List<ResolveInfo> allHomeCandidates = new ArrayList<>();

            // Default launcher from package manager.
            final long startGetHomeActivitiesAsUser = injectElapsedRealtime();
            final ComponentName defaultLauncher = injectPackageManagerInternal()
            final ComponentName defaultLauncher = mPackageManagerInternal
                    .getHomeActivitiesAsUser(allHomeCandidates, userId);
            logDurationStat(Stats.GET_DEFAULT_HOME, startGetHomeActivitiesAsUser);

@@ -1950,7 +1968,7 @@ public class ShortcutService extends IShortcutService.Stub {
                    Slog.v(TAG, "Default launcher from PM: " + detected);
                }
            } else {
                detected = user.getDefaultLauncherComponent();
                detected = user.getLastKnownLauncher();

                if (detected != null) {
                    if (injectIsActivityEnabledAndExported(detected, userId)) {
@@ -1960,7 +1978,7 @@ public class ShortcutService extends IShortcutService.Stub {
                    } else {
                        Slog.w(TAG, "Cached launcher " + detected + " no longer exists");
                        detected = null;
                        user.setDefaultLauncherComponent(null);
                        user.clearLauncher();
                    }
                }
            }
@@ -1991,13 +2009,13 @@ public class ShortcutService extends IShortcutService.Stub {
                    lastPriority = ri.priority;
                }
            }
            logDurationStat(Stats.LAUNCHER_PERMISSION_CHECK, start);

            // Update the cache.
            user.setLauncher(detected);
            if (detected != null) {
                if (DEBUG) {
                    Slog.v(TAG, "Detected launcher: " + detected);
                }
                user.setDefaultLauncherComponent(detected);
                return detected.getPackageName().equals(callingPackage);
            } else {
                // Default launcher not found.
@@ -2358,6 +2376,17 @@ public class ShortcutService extends IShortcutService.Stub {
                    return;
                }

                // Whenever we get one of those package broadcasts, or get
                // ACTION_PREFERRED_ACTIVITY_CHANGED, we purge the default launcher cache.
                synchronized (mLock) {
                    final ShortcutUser user = getUserShortcutsLocked(userId);
                    user.clearLauncher();
                }
                if (Intent.ACTION_PREFERRED_ACTIVITY_CHANGED.equals(action)) {
                    // Nothing farther to do.
                    return;
                }

                final Uri intentUri = intent.getData();
                final String packageName = (intentUri != null) ? intentUri.getSchemeSpecificPart()
                        : null;
@@ -3260,7 +3289,7 @@ public class ShortcutService extends IShortcutService.Stub {

        private void clearLauncher() {
            synchronized (mLock) {
                getUserShortcutsLocked(mUserId).setDefaultLauncherComponent(null);
                getUserShortcutsLocked(mUserId).forceClearLauncher();
            }
        }

@@ -3270,7 +3299,7 @@ public class ShortcutService extends IShortcutService.Stub {
                hasShortcutHostPermissionInner("-", mUserId);

                getOutPrintWriter().println("Launcher: "
                        + getUserShortcutsLocked(mUserId).getDefaultLauncherComponent());
                        + getUserShortcutsLocked(mUserId).getLastKnownLauncher());
            }
        }

@@ -3394,11 +3423,6 @@ public class ShortcutService extends IShortcutService.Stub {
        }
    }

    @VisibleForTesting
    PackageManagerInternal injectPackageManagerInternal() {
        return mPackageManagerInternal;
    }

    File getUserBitmapFilePath(@UserIdInt int userId) {
        return new File(injectUserDataPath(userId), DIRECTORY_BITMAPS);
    }
@@ -3482,7 +3506,7 @@ public class ShortcutService extends IShortcutService.Stub {
    }

    private void verifyStatesInner() {
        synchronized (this) {
        synchronized (mLock) {
            forEachLoadedUserLocked(u -> u.forAllPackageItems(ShortcutPackageItem::verifyStates));
        }
    }
+49 −12
Original line number Diff line number Diff line
@@ -103,8 +103,15 @@ class ShortcutUser {

    private final ArrayMap<PackageWithUser, ShortcutLauncher> mLaunchers = new ArrayMap<>();

    /** Default launcher that can access the launcher apps APIs. */
    private ComponentName mDefaultLauncherComponent;
    /**
     * Last known launcher.  It's used when the default launcher isn't set in PM -- i.e.
     * when getHomeActivitiesAsUser() return null.  We need it so that in this situation the
     * previously default launcher can still access shortcuts.
     */
    private ComponentName mLastKnownLauncher;

    /** In-memory-cached default launcher. */
    private ComponentName mCachedLauncher;

    private String mKnownLocales;

@@ -304,8 +311,7 @@ class ShortcutUser {
        ShortcutService.writeAttr(out, ATTR_LAST_APP_SCAN_TIME,
                mLastAppScanTime);

        ShortcutService.writeTagValue(out, TAG_LAUNCHER,
                mDefaultLauncherComponent);
        ShortcutService.writeTagValue(out, TAG_LAUNCHER, mLastKnownLauncher);

        // Can't use forEachPackageItem due to the checked exceptions.
        {
@@ -364,7 +370,7 @@ class ShortcutUser {
            if (depth == outerDepth + 1) {
                switch (tag) {
                    case TAG_LAUNCHER: {
                        ret.mDefaultLauncherComponent = ShortcutService.parseComponentNameAttribute(
                        ret.mLastKnownLauncher = ShortcutService.parseComponentNameAttribute(
                                parser, ATTR_VALUE);
                        continue;
                    }
@@ -389,18 +395,44 @@ class ShortcutUser {
        return ret;
    }

    public ComponentName getDefaultLauncherComponent() {
        return mDefaultLauncherComponent;
    public ComponentName getLastKnownLauncher() {
        return mLastKnownLauncher;
    }

    public void setLauncher(ComponentName launcherComponent) {
        setLauncher(launcherComponent, /* allowPurgeLastKnown */ false);
    }

    public void setDefaultLauncherComponent(ComponentName launcherComponent) {
        if (Objects.equal(mDefaultLauncherComponent, launcherComponent)) {
    /** Clears the launcher information without clearing the last known one */
    public void clearLauncher() {
        setLauncher(null);
    }

    /**
     * Clears the launcher information *with(* clearing the last known one; we do this witl
     * "cmd shortcut clear-default-launcher".
     */
    public void forceClearLauncher() {
        setLauncher(null, /* allowPurgeLastKnown */ true);
    }

    private void setLauncher(ComponentName launcherComponent, boolean allowPurgeLastKnown) {
        mCachedLauncher = launcherComponent; // Always update the in-memory cache.

        if (Objects.equal(mLastKnownLauncher, launcherComponent)) {
            return;
        }
        mDefaultLauncherComponent = launcherComponent;
        if (!allowPurgeLastKnown && launcherComponent == null) {
            return;
        }
        mLastKnownLauncher = launcherComponent;
        mService.scheduleSaveUser(mUserId);
    }

    public ComponentName getCachedLauncher() {
        return mCachedLauncher;
    }

    public void resetThrottling() {
        for (int i = mPackages.size() - 1; i >= 0; i--) {
            mPackages.valueAt(i).resetThrottling();
@@ -422,8 +454,13 @@ class ShortcutUser {
        prefix += prefix + "  ";

        pw.print(prefix);
        pw.print("Default launcher: ");
        pw.print(mDefaultLauncherComponent);
        pw.print("Cached launcher: ");
        pw.print(mCachedLauncher);
        pw.println();

        pw.print(prefix);
        pw.print("Last known launcher: ");
        pw.print(mLastKnownLauncher);
        pw.println();

        for (int i = 0; i < mLaunchers.size(); i++) {
Loading