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

Commit 5f8a0114 authored by Pinyao Ting's avatar Pinyao Ting Committed by Android (Google) Code Review
Browse files

Merge "Move bitmap saving into corresponding ShortcutPackage" into tm-dev

parents dfc0bae5 29beab87
Loading
Loading
Loading
Loading
+30 −4
Original line number Diff line number Diff line
@@ -349,7 +349,7 @@ class ShortcutPackage extends ShortcutPackageItem {
    private ShortcutInfo forceDeleteShortcutInner(@NonNull String id) {
        final ShortcutInfo shortcut = mShortcuts.remove(id);
        if (shortcut != null) {
            mShortcutUser.mService.removeIconLocked(shortcut);
            removeIcon(shortcut);
            shortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_PINNED
                    | ShortcutInfo.FLAG_MANIFEST | ShortcutInfo.FLAG_CACHED_ALL);
        }
@@ -366,7 +366,7 @@ class ShortcutPackage extends ShortcutPackageItem {
        forceDeleteShortcutInner(newShortcut.getId());

        // Extract Icon and update the icon res ID and the bitmap path.
        s.saveIconAndFixUpShortcutLocked(newShortcut);
        s.saveIconAndFixUpShortcutLocked(this, newShortcut);
        s.fixUpShortcutResourceNamesAndValues(newShortcut);
        saveShortcut(newShortcut);
    }
@@ -972,7 +972,8 @@ class ShortcutPackage extends ShortcutPackageItem {
    /**
     * Return the filenames (excluding path names) of icon bitmap files from this package.
     */
    public ArraySet<String> getUsedBitmapFiles() {
    @GuardedBy("mLock")
    private ArraySet<String> getUsedBitmapFilesLocked() {
        final ArraySet<String> usedFiles = new ArraySet<>(1);
        forEachShortcut(si -> {
            if (si.getBitmapPath() != null) {
@@ -982,6 +983,26 @@ class ShortcutPackage extends ShortcutPackageItem {
        return usedFiles;
    }

    public void cleanupDanglingBitmapFiles(@NonNull File path) {
        synchronized (mLock) {
            mShortcutBitmapSaver.waitForAllSavesLocked();
            final ArraySet<String> usedFiles = getUsedBitmapFilesLocked();

            for (File child : path.listFiles()) {
                if (!child.isFile()) {
                    continue;
                }
                final String name = child.getName();
                if (!usedFiles.contains(name)) {
                    if (ShortcutService.DEBUG) {
                        Slog.d(TAG, "Removing dangling bitmap file: " + child.getAbsolutePath());
                    }
                    child.delete();
                }
            }
        }
    }

    private static String getFileName(@NonNull String path) {
        final int sep = path.lastIndexOf(File.separatorChar);
        if (sep == -1) {
@@ -1608,6 +1629,11 @@ class ShortcutPackage extends ShortcutPackageItem {
        pw.print(" (");
        pw.print(Formatter.formatFileSize(mShortcutUser.mService.mContext, totalBitmapSize[0]));
        pw.println(")");

        pw.println();
        synchronized (mLock) {
            mShortcutBitmapSaver.dumpLocked(pw, "  ");
        }
    }

    public void dumpShortcuts(@NonNull PrintWriter pw, int matchFlags) {
@@ -1729,7 +1755,7 @@ class ShortcutPackage extends ShortcutPackageItem {
        // Note: at this point no shortcuts should have bitmaps pending save, but if they do,
        // just remove the bitmap.
        if (si.isIconPendingSave()) {
            s.removeIconLocked(si);
            removeIcon(si);
        }
        out.startTag(null, TAG_SHORTCUT);
        ShortcutService.writeAttr(out, ATTR_ID, si.getId());
+36 −1
Original line number Diff line number Diff line
@@ -16,8 +16,10 @@
package com.android.server.pm;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.pm.PackageInfo;
import android.content.pm.ShortcutInfo;
import android.graphics.Bitmap;
import android.util.AtomicFile;
import android.util.Slog;
import android.util.TypedXmlSerializer;
@@ -50,6 +52,9 @@ abstract class ShortcutPackageItem {

    protected ShortcutUser mShortcutUser;

    @GuardedBy("mLock")
    protected ShortcutBitmapSaver mShortcutBitmapSaver;

    protected final Object mLock = new Object();

    protected ShortcutPackageItem(@NonNull ShortcutUser shortcutUser,
@@ -59,6 +64,7 @@ abstract class ShortcutPackageItem {
        mPackageUserId = packageUserId;
        mPackageName = Preconditions.checkStringNotEmpty(packageName);
        mPackageInfo = Objects.requireNonNull(packageInfo);
        mShortcutBitmapSaver = new ShortcutBitmapSaver(shortcutUser.mService);
    }

    /**
@@ -206,7 +212,7 @@ abstract class ShortcutPackageItem {

    void saveShortcutPackageItem() {
        // Wait for bitmap saves to conclude before proceeding to saving shortcuts.
        mShortcutUser.mService.waitForBitmapSaves();
        waitForBitmapSaves();
        // Save each ShortcutPackageItem in a separate Xml file.
        final File path = getShortcutPackageItemFile();
        if (ShortcutService.DEBUG || ShortcutService.DEBUG_REBOOT) {
@@ -221,6 +227,35 @@ abstract class ShortcutPackageItem {
        }
    }

    public boolean waitForBitmapSaves() {
        synchronized (mLock) {
            return mShortcutBitmapSaver.waitForAllSavesLocked();
        }
    }

    public void saveBitmap(ShortcutInfo shortcut,
            int maxDimension, Bitmap.CompressFormat format, int quality) {
        synchronized (mLock) {
            mShortcutBitmapSaver.saveBitmapLocked(shortcut, maxDimension, format, quality);
        }
    }

    /**
     * Wait for all pending saves to finish, and then return the given shortcut's bitmap path.
     */
    @Nullable
    public String getBitmapPathMayWait(ShortcutInfo shortcut) {
        synchronized (mLock) {
            return mShortcutBitmapSaver.getBitmapPathMayWaitLocked(shortcut);
        }
    }

    public void removeIcon(ShortcutInfo shortcut) {
        synchronized (mLock) {
            mShortcutBitmapSaver.removeIcon(shortcut);
        }
    }

    void removeShortcutPackageItem() {
        synchronized (mLock) {
            getShortcutPackageItemFile().delete();
+20 −56
Original line number Diff line number Diff line
@@ -363,7 +363,6 @@ public class ShortcutService extends IShortcutService.Stub {
    private final RoleManager mRoleManager;

    private final ShortcutRequestPinProcessor mShortcutRequestPinProcessor;
    private final ShortcutBitmapSaver mShortcutBitmapSaver;
    private final ShortcutDumpFiles mShortcutDumpFiles;

    @GuardedBy("mLock")
@@ -490,7 +489,6 @@ public class ShortcutService extends IShortcutService.Stub {
        mRoleManager = Objects.requireNonNull(mContext.getSystemService(RoleManager.class));

        mShortcutRequestPinProcessor = new ShortcutRequestPinProcessor(this, mLock);
        mShortcutBitmapSaver = new ShortcutBitmapSaver(this);
        mShortcutDumpFiles = new ShortcutDumpFiles(this);
        mIsAppSearchEnabled = DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI,
                SystemUiDeviceConfigFlags.SHORTCUT_APPSEARCH_INTEGRATION, true)
@@ -1063,8 +1061,6 @@ public class ShortcutService extends IShortcutService.Stub {
            Slog.d(TAG, "Saving to " + path);
        }

        mShortcutBitmapSaver.waitForAllSavesLocked();

        path.getParentFile().mkdirs();
        final AtomicFile file = new AtomicFile(path);
        FileOutputStream os = null;
@@ -1388,15 +1384,12 @@ public class ShortcutService extends IShortcutService.Stub {

    // === Caller validation ===

    void removeIconLocked(ShortcutInfo shortcut) {
        mShortcutBitmapSaver.removeIcon(shortcut);
    }

    public void cleanupBitmapsForPackage(@UserIdInt int userId, String packageName) {
        final File packagePath = new File(getUserBitmapFilePath(userId), packageName);
        if (!packagePath.isDirectory()) {
            return;
        }
        // ShortcutPackage is already removed at this point, we can safely remove the folder.
        if (!(FileUtils.deleteContents(packagePath) && packagePath.delete())) {
            Slog.w(TAG, "Unable to remove directory " + packagePath);
        }
@@ -1437,38 +1430,12 @@ public class ShortcutService extends IShortcutService.Stub {
                }
                cleanupBitmapsForPackage(userId, packageName);
            } else {
                cleanupDanglingBitmapFilesLocked(userId, user, packageName, child);
                user.getPackageShortcuts(packageName).cleanupDanglingBitmapFiles(child);
            }
        }
        logDurationStat(Stats.CLEANUP_DANGLING_BITMAPS, start);
    }

    /**
     * Remove dangling bitmap files for a package.
     *
     * Note this method must be called with the lock held after calling
     * {@link ShortcutBitmapSaver#waitForAllSavesLocked()} to make sure there's no pending bitmap
     * saves are going on.
     */
    private void cleanupDanglingBitmapFilesLocked(@UserIdInt int userId, @NonNull ShortcutUser user,
            @NonNull String packageName, @NonNull File path) {
        final ArraySet<String> usedFiles =
                user.getPackageShortcuts(packageName).getUsedBitmapFiles();

        for (File child : path.listFiles()) {
            if (!child.isFile()) {
                continue;
            }
            final String name = child.getName();
            if (!usedFiles.contains(name)) {
                if (DEBUG) {
                    Slog.d(TAG, "Removing dangling bitmap file: " + child.getAbsolutePath());
                }
                child.delete();
            }
        }
    }

    @VisibleForTesting
    static class FileOutputStreamWithPath extends FileOutputStream {
        private final File mFile;
@@ -1513,7 +1480,7 @@ public class ShortcutService extends IShortcutService.Stub {
        }
    }

    void saveIconAndFixUpShortcutLocked(ShortcutInfo shortcut) {
    void saveIconAndFixUpShortcutLocked(ShortcutPackage p, ShortcutInfo shortcut) {
        if (shortcut.hasIconFile() || shortcut.hasIconResource() || shortcut.hasIconUri()) {
            return;
        }
@@ -1521,7 +1488,7 @@ public class ShortcutService extends IShortcutService.Stub {
        final long token = injectClearCallingIdentity();
        try {
            // Clear icon info on the shortcut.
            removeIconLocked(shortcut);
            p.removeIcon(shortcut);

            final Icon icon = shortcut.getIcon();
            if (icon == null) {
@@ -1560,8 +1527,7 @@ public class ShortcutService extends IShortcutService.Stub {
                        // just in case.
                        throw ShortcutInfo.getInvalidIconException();
                }
                mShortcutBitmapSaver.saveBitmapLocked(shortcut,
                        maxIconDimension, mIconPersistFormat, mIconPersistQuality);
                p.saveBitmap(shortcut, maxIconDimension, mIconPersistFormat, mIconPersistQuality);
            } finally {
                // Once saved, we won't use the original icon information, so null it out.
                shortcut.clearIcon();
@@ -2110,7 +2076,7 @@ public class ShortcutService extends IShortcutService.Stub {

                    final boolean replacingIcon = (source.getIcon() != null);
                    if (replacingIcon) {
                        removeIconLocked(target);
                        ps.removeIcon(target);
                    }

                    // Note copyNonNullFieldsFrom() does the "updatable with?" check too.
@@ -2118,7 +2084,7 @@ public class ShortcutService extends IShortcutService.Stub {
                    target.setTimestamp(injectCurrentTimeMillis());

                    if (replacingIcon) {
                        saveIconAndFixUpShortcutLocked(target);
                        saveIconAndFixUpShortcutLocked(ps, target);
                    }

                    // When we're updating any resource related fields, re-extract the res
@@ -3463,7 +3429,7 @@ public class ShortcutService extends IShortcutService.Stub {
                if (shortcutInfo == null) {
                    return null;
                }
                return getShortcutIconParcelFileDescriptor(shortcutInfo);
                return getShortcutIconParcelFileDescriptor(p, shortcutInfo);
            }
        }

@@ -3476,6 +3442,7 @@ public class ShortcutService extends IShortcutService.Stub {
            Objects.requireNonNull(shortcutId, "shortcutId");

            // Checks shortcuts in memory first
            final ShortcutPackage p;
            synchronized (mLock) {
                throwIfUserLockedL(userId);
                throwIfUserLockedL(launcherUserId);
@@ -3483,8 +3450,7 @@ public class ShortcutService extends IShortcutService.Stub {
                getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
                        .attemptToRestoreIfNeededAndSave();

                final ShortcutPackage p = getUserShortcutsLocked(userId)
                        .getPackageShortcutsIfExists(packageName);
                p = getUserShortcutsLocked(userId).getPackageShortcutsIfExists(packageName);
                if (p == null) {
                    cb.complete(null);
                    return;
@@ -3492,24 +3458,23 @@ public class ShortcutService extends IShortcutService.Stub {

                final ShortcutInfo shortcutInfo = p.findShortcutById(shortcutId);
                if (shortcutInfo != null) {
                    cb.complete(getShortcutIconParcelFileDescriptor(shortcutInfo));
                    cb.complete(getShortcutIconParcelFileDescriptor(p, shortcutInfo));
                    return;
                }
            }

            // Otherwise check persisted shortcuts
            getShortcutInfoAsync(launcherUserId, packageName, shortcutId, userId, si -> {
                cb.complete(getShortcutIconParcelFileDescriptor(si));
            });
            getShortcutInfoAsync(launcherUserId, packageName, shortcutId, userId, si ->
                    cb.complete(getShortcutIconParcelFileDescriptor(p, si)));
        }

        @Nullable
        private ParcelFileDescriptor getShortcutIconParcelFileDescriptor(
                @Nullable final ShortcutInfo shortcutInfo) {
            if (shortcutInfo == null || !shortcutInfo.hasIconFile()) {
                @Nullable final ShortcutPackage p, @Nullable final ShortcutInfo shortcutInfo) {
            if (p == null || shortcutInfo == null || !shortcutInfo.hasIconFile()) {
                return null;
            }
            final String path = mShortcutBitmapSaver.getBitmapPathMayWaitLocked(shortcutInfo);
            final String path = p.getBitmapPathMayWait(shortcutInfo);
            if (path == null) {
                Slog.w(TAG, "null bitmap detected in getShortcutIconFd()");
                return null;
@@ -4771,9 +4736,6 @@ public class ShortcutService extends IShortcutService.Stub {
                    pw.println(Log.getStackTraceString(mLastWtfStacktrace));
                }

                pw.println();
                mShortcutBitmapSaver.dumpLocked(pw, "  ");

                pw.println();
            }

@@ -5347,9 +5309,11 @@ public class ShortcutService extends IShortcutService.Stub {
        }
    }

    void waitForBitmapSaves() {
    @VisibleForTesting
    void waitForBitmapSavesForTest() {
        synchronized (mLock) {
            mShortcutBitmapSaver.waitForAllSavesLocked();
            forEachLoadedUserLocked(u ->
                    u.forAllPackageItems(ShortcutPackageItem::waitForBitmapSaves));
        }
    }

+1 −0
Original line number Diff line number Diff line
@@ -401,6 +401,7 @@ class ShortcutUser {

    private void saveShortcutPackageItem(TypedXmlSerializer out, ShortcutPackageItem spi,
            boolean forBackup) throws IOException, XmlPullParserException {
        spi.waitForBitmapSaves();
        if (forBackup) {
            if (spi.getPackageUserId() != spi.getOwnerUserId()) {
                return; // Don't save cross-user information.
+3 −3
Original line number Diff line number Diff line
@@ -1975,7 +1975,7 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
        if (si == null) {
            return null;
        }
        mService.waitForBitmapSaves();
        mService.waitForBitmapSavesForTest();
        return new File(si.getBitmapPath()).getName();
    }

@@ -1984,7 +1984,7 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
        if (si == null) {
            return null;
        }
        mService.waitForBitmapSaves();
        mService.waitForBitmapSavesForTest();
        return new File(si.getBitmapPath()).getAbsolutePath();
    }

@@ -2139,7 +2139,7 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
    }

    protected boolean bitmapDirectoryExists(String packageName, int userId) {
        mService.waitForBitmapSaves();
        mService.waitForBitmapSavesForTest();
        final File path = new File(mService.getUserBitmapFilePath(userId), packageName);
        return path.isDirectory();
    }
Loading