Loading services/core/java/com/android/server/pm/ShortcutBackupAgent.java→core/java/com/android/server/backup/ShortcutBackupHelper.java +70 −0 Original line number Diff line number Diff line Loading @@ -13,25 +13,58 @@ * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.pm; package com.android.server.backup; import android.app.backup.BlobBackupHelper; import android.content.Context; import android.content.pm.IShortcutService; import android.os.ServiceManager; import android.os.UserHandle; import android.util.Slog; public class ShortcutBackupAgent extends BlobBackupHelper { public class ShortcutBackupHelper extends BlobBackupHelper { private static final String TAG = "ShortcutBackupAgent"; private static final int BLOB_VERSION = 1; public ShortcutBackupAgent(int currentBlobVersion, String... keys) { super(currentBlobVersion, keys); private static final String KEY_USER_FILE = "shortcutuser.xml"; public ShortcutBackupHelper() { super(BLOB_VERSION, KEY_USER_FILE); } private IShortcutService getShortcutService() { return IShortcutService.Stub.asInterface( ServiceManager.getService(Context.SHORTCUT_SERVICE)); } @Override protected byte[] getBackupPayload(String key) { throw new RuntimeException("not implemented yet"); // todo switch (key) { case KEY_USER_FILE: try { return getShortcutService().getBackupPayload(UserHandle.USER_SYSTEM); } catch (Exception e) { Slog.wtf(TAG, "Backup failed", e); } break; default: Slog.w(TAG, "Unknown key: " + key); } return null; } @Override protected void applyRestoredPayload(String key, byte[] payload) { throw new RuntimeException("not implemented yet"); // todo switch (key) { case KEY_USER_FILE: try { getShortcutService().applyRestore(payload, UserHandle.USER_SYSTEM); } catch (Exception e) { Slog.wtf(TAG, "Restore failed", e); } break; default: Slog.w(TAG, "Unknown key: " + key); } } } core/java/com/android/server/backup/SystemBackupAgent.java +4 −1 Original line number Diff line number Diff line Loading @@ -17,9 +17,9 @@ package com.android.server.backup; import android.app.IWallpaperManager; import android.app.backup.BackupAgentHelper; import android.app.backup.BackupDataInput; import android.app.backup.BackupDataOutput; import android.app.backup.BackupAgentHelper; import android.app.backup.FullBackup; import android.app.backup.FullBackupDataOutput; import android.app.backup.WallpaperBackupHelper; Loading Loading @@ -48,6 +48,7 @@ public class SystemBackupAgent extends BackupAgentHelper { private static final String NOTIFICATION_HELPER = "notifications"; private static final String PERMISSION_HELPER = "permissions"; private static final String USAGE_STATS_HELPER = "usage_stats"; private static final String SHORTCUT_MANAGER_HELPER = "shortcut_manager"; // These paths must match what the WallpaperManagerService uses. The leaf *_FILENAME // are also used in the full-backup file format, so must not change unless steps are Loading Loading @@ -100,6 +101,7 @@ public class SystemBackupAgent extends BackupAgentHelper { addHelper(NOTIFICATION_HELPER, new NotificationBackupHelper(this)); addHelper(PERMISSION_HELPER, new PermissionBackupHelper()); addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(this)); addHelper(SHORTCUT_MANAGER_HELPER, new ShortcutBackupHelper()); super.onBackup(oldState, data, newState); } Loading Loading @@ -138,6 +140,7 @@ public class SystemBackupAgent extends BackupAgentHelper { addHelper(NOTIFICATION_HELPER, new NotificationBackupHelper(this)); addHelper(PERMISSION_HELPER, new PermissionBackupHelper()); addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(this)); addHelper(SHORTCUT_MANAGER_HELPER, new ShortcutBackupHelper()); try { super.onRestore(data, appVersionCode, newState); Loading services/core/java/com/android/server/pm/ShortcutLauncher.java +70 −22 Original line number Diff line number Diff line Loading @@ -20,6 +20,10 @@ import android.annotation.UserIdInt; import android.content.pm.ShortcutInfo; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.server.pm.ShortcutUser.PackageWithUser; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; Loading @@ -27,6 +31,7 @@ import org.xmlpull.v1.XmlSerializer; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; /** Loading @@ -43,15 +48,16 @@ class ShortcutLauncher extends ShortcutPackageItem { private static final String ATTR_LAUNCHER_USER_ID = "launcher-user"; private static final String ATTR_VALUE = "value"; private static final String ATTR_PACKAGE_NAME = "package-name"; private static final String ATTR_PACKAGE_USER_ID = "package-user"; private final int mOwnerUserId; /** * Package name -> IDs. */ final private ArrayMap<String, ArraySet<String>> mPinnedShortcuts = new ArrayMap<>(); final private ArrayMap<PackageWithUser, ArraySet<String>> mPinnedShortcuts = new ArrayMap<>(); public ShortcutLauncher(@UserIdInt int ownerUserId, @NonNull String packageName, private ShortcutLauncher(@UserIdInt int ownerUserId, @NonNull String packageName, @UserIdInt int launcherUserId, ShortcutPackageInfo spi) { super(launcherUserId, packageName, spi != null ? spi : ShortcutPackageInfo.newEmpty()); mOwnerUserId = ownerUserId; Loading @@ -59,7 +65,7 @@ class ShortcutLauncher extends ShortcutPackageItem { public ShortcutLauncher(@UserIdInt int ownerUserId, @NonNull String packageName, @UserIdInt int launcherUserId) { this(launcherUserId, packageName, launcherUserId, null); this(ownerUserId, packageName, launcherUserId, null); } @Override Loading @@ -67,16 +73,38 @@ class ShortcutLauncher extends ShortcutPackageItem { return mOwnerUserId; } /** * Called when the new package can't receive the backup, due to signature or version mismatch. */ @Override protected void onRestoreBlocked(ShortcutService s) { final ArrayList<PackageWithUser> pinnedPackages = new ArrayList<>(mPinnedShortcuts.keySet()); mPinnedShortcuts.clear(); for (int i = pinnedPackages.size() - 1; i >= 0; i--) { final PackageWithUser pu = pinnedPackages.get(i); s.getPackageShortcutsLocked(pu.packageName, pu.userId) .refreshPinnedFlags(s); } } @Override protected void onRestored(ShortcutService s) { // Nothing to do. } public void pinShortcuts(@NonNull ShortcutService s, @UserIdInt int packageUserId, @NonNull String packageName, @NonNull List<String> ids) { final ShortcutPackage packageShortcuts = s.getPackageShortcutsLocked(packageName, packageUserId); final PackageWithUser pu = PackageWithUser.of(packageUserId, packageName); final int idSize = ids.size(); if (idSize == 0) { mPinnedShortcuts.remove(packageName); mPinnedShortcuts.remove(pu); } else { final ArraySet<String> prevSet = mPinnedShortcuts.get(packageName); final ArraySet<String> prevSet = mPinnedShortcuts.get(pu); // Pin shortcuts. Make sure only pin the ones that were visible to the caller. // i.e. a non-dynamic, pinned shortcut by *other launchers* shouldn't be pinned here. Loading @@ -93,7 +121,7 @@ class ShortcutLauncher extends ShortcutPackageItem { newSet.add(id); } } mPinnedShortcuts.put(packageName, newSet); mPinnedShortcuts.put(pu, newSet); } packageShortcuts.refreshPinnedFlags(s); } Loading @@ -101,12 +129,13 @@ class ShortcutLauncher extends ShortcutPackageItem { /** * Return the pinned shortcut IDs for the publisher package. */ public ArraySet<String> getPinnedShortcutIds(@NonNull String packageName) { return mPinnedShortcuts.get(packageName); public ArraySet<String> getPinnedShortcutIds(@NonNull String packageName, @UserIdInt int packageUserId) { return mPinnedShortcuts.get(PackageWithUser.of(packageUserId, packageName)); } boolean cleanUpPackage(String packageName) { return mPinnedShortcuts.remove(packageName) != null; boolean cleanUpPackage(String packageName, @UserIdInt int packageUserId) { return mPinnedShortcuts.remove(PackageWithUser.of(packageUserId, packageName)) != null; } /** Loading @@ -126,9 +155,15 @@ class ShortcutLauncher extends ShortcutPackageItem { getPackageInfo().saveToXml(out); for (int i = 0; i < size; i++) { final PackageWithUser pu = mPinnedShortcuts.keyAt(i); if (forBackup && (pu.userId != getOwnerUserId())) { continue; // Target package on a different user, skip. (i.e. work profile) } out.startTag(null, TAG_PACKAGE); ShortcutService.writeAttr(out, ATTR_PACKAGE_NAME, mPinnedShortcuts.keyAt(i)); ShortcutService.writeAttr(out, ATTR_PACKAGE_NAME, pu.packageName); ShortcutService.writeAttr(out, ATTR_PACKAGE_USER_ID, pu.userId); final ArraySet<String> ids = mPinnedShortcuts.valueAt(i); final int idSize = ids.size(); Loading Loading @@ -157,8 +192,6 @@ class ShortcutLauncher extends ShortcutPackageItem { final ShortcutLauncher ret = new ShortcutLauncher(launcherUserId, launcherPackageName, launcherUserId); ShortcutPackageInfo spi = null; ArraySet<String> ids = null; final int outerDepth = parser.getDepth(); int type; Loading @@ -172,13 +205,17 @@ class ShortcutLauncher extends ShortcutPackageItem { if (depth == outerDepth + 1) { switch (tag) { case ShortcutPackageInfo.TAG_ROOT: spi = ShortcutPackageInfo.loadFromXml(parser); ret.getPackageInfo().loadFromXml(parser, fromBackup); continue; case TAG_PACKAGE: { final String packageName = ShortcutService.parseStringAttribute(parser, ATTR_PACKAGE_NAME); final int packageUserId = fromBackup ? ownerUserId : ShortcutService.parseIntAttribute(parser, ATTR_PACKAGE_USER_ID, ownerUserId); ids = new ArraySet<>(); ret.mPinnedShortcuts.put(packageName, ids); ret.mPinnedShortcuts.put( PackageWithUser.of(packageUserId, packageName), ids); continue; } } Loading @@ -186,17 +223,17 @@ class ShortcutLauncher extends ShortcutPackageItem { if (depth == outerDepth + 2) { switch (tag) { case TAG_PIN: { ids.add(ShortcutService.parseStringAttribute(parser, ATTR_VALUE)); if (ids == null) { Slog.w(TAG, TAG_PIN + " in invalid place"); } else { ids.add(ShortcutService.parseStringAttribute(parser, ATTR_VALUE)); } continue; } } } ShortcutService.warnForInvalidTag(depth, tag); } if (spi != null) { ret.replacePackageInfo(spi); } return ret; } Loading @@ -208,6 +245,8 @@ class ShortcutLauncher extends ShortcutPackageItem { pw.print(getPackageName()); pw.print(" Package user: "); pw.print(getPackageUserId()); pw.print(" Owner user: "); pw.print(getOwnerUserId()); pw.println(); getPackageInfo().dump(s, pw, prefix + " "); Loading @@ -217,10 +256,14 @@ class ShortcutLauncher extends ShortcutPackageItem { for (int i = 0; i < size; i++) { pw.println(); final PackageWithUser pu = mPinnedShortcuts.keyAt(i); pw.print(prefix); pw.print(" "); pw.print("Package: "); pw.println(mPinnedShortcuts.keyAt(i)); pw.print(pu.packageName); pw.print(" User: "); pw.println(pu.userId); final ArraySet<String> ids = mPinnedShortcuts.valueAt(i); final int idSize = ids.size(); Loading @@ -233,4 +276,9 @@ class ShortcutLauncher extends ShortcutPackageItem { } } } @VisibleForTesting ArraySet<String> getAllPinnedShortcutsForTest(String packageName, int packageUserId) { return new ArraySet<>(mPinnedShortcuts.get(PackageWithUser.of(packageUserId, packageName))); } } services/core/java/com/android/server/pm/ShortcutPackage.java +42 −14 Original line number Diff line number Diff line Loading @@ -26,6 +26,8 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; Loading @@ -34,6 +36,7 @@ import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.function.Predicate; Loading Loading @@ -83,7 +86,7 @@ class ShortcutPackage extends ShortcutPackageItem { */ private long mLastResetTime; public ShortcutPackage(int packageUserId, String packageName, ShortcutPackageInfo spi) { private ShortcutPackage(int packageUserId, String packageName, ShortcutPackageInfo spi) { super(packageUserId, packageName, spi != null ? spi : ShortcutPackageInfo.newEmpty()); } Loading @@ -97,6 +100,19 @@ class ShortcutPackage extends ShortcutPackageItem { return getPackageUserId(); } @Override protected void onRestoreBlocked(ShortcutService s) { // Can't restore due to version/signature mismatch. Remove all shortcuts. mShortcuts.clear(); } @Override protected void onRestored(ShortcutService s) { // Because some launchers may not have been restored (e.g. allowBackup=false), // we need to re-calculate the pinned shortcuts. refreshPinnedFlags(s); } /** * Note this does *not* provide a correct view to the calling launcher. */ Loading Loading @@ -229,20 +245,26 @@ class ShortcutPackage extends ShortcutPackageItem { s.getUserShortcutsLocked(getPackageUserId()).getAllLaunchers(); for (int l = launchers.size() - 1; l >= 0; l--) { // Note even if a launcher that hasn't been installed can still pin shortcuts. final ShortcutLauncher launcherShortcuts = launchers.valueAt(l); final ArraySet<String> pinned = launcherShortcuts.getPinnedShortcutIds( getPackageName()); getPackageName(), getPackageUserId()); if (pinned == null || pinned.size() == 0) { continue; } for (int i = pinned.size() - 1; i >= 0; i--) { final ShortcutInfo si = mShortcuts.get(pinned.valueAt(i)); final String id = pinned.valueAt(i); final ShortcutInfo si = mShortcuts.get(id); if (si == null) { s.wtf("Shortcut not found"); } else { si.addFlags(ShortcutInfo.FLAG_PINNED); // This happens if a launcher pinned shortcuts from this package, then backup& // restored, but this package doesn't allow backing up. // In that case the launcher ends up having a dangling pinned shortcuts. // That's fine, when the launcher is restored, we'll fix it. continue; } si.addFlags(ShortcutInfo.FLAG_PINNED); } } Loading Loading @@ -312,11 +334,15 @@ class ShortcutPackage extends ShortcutPackageItem { public void findAll(@NonNull ShortcutService s, @NonNull List<ShortcutInfo> result, @Nullable Predicate<ShortcutInfo> query, int cloneFlag, @Nullable String callingLauncher, int launcherUserId) { if (getPackageInfo().isShadow()) { // Restored and the app not installed yet, so don't return any. return; } // Set of pinned shortcuts by the calling launcher. final ArraySet<String> pinnedByCallerSet = (callingLauncher == null) ? null : s.getLauncherShortcuts(callingLauncher, getPackageUserId(), launcherUserId) .getPinnedShortcutIds(getPackageName()); : s.getLauncherShortcutsLocked(callingLauncher, getPackageUserId(), launcherUserId) .getPinnedShortcutIds(getPackageName(), getPackageUserId()); for (int i = 0; i < mShortcuts.size(); i++) { final ShortcutInfo si = mShortcuts.valueAt(i); Loading @@ -328,7 +354,8 @@ class ShortcutPackage extends ShortcutPackageItem { || ((pinnedByCallerSet != null) && pinnedByCallerSet.contains(si.getId())); if (!si.isDynamic()) { if (!si.isPinned()) { s.wtf("Shortcut not pinned here"); s.wtf("Shortcut not pinned: package " + getPackageName() + ", user=" + getPackageUserId() + ", id=" + si.getId()); continue; } if (!isPinnedByCaller) { Loading Loading @@ -479,7 +506,6 @@ class ShortcutPackage extends ShortcutPackageItem { ShortcutService.parseIntAttribute(parser, ATTR_CALL_COUNT); ret.mLastResetTime = ShortcutService.parseLongAttribute(parser, ATTR_LAST_RESET); ShortcutPackageInfo spi = null; final int outerDepth = parser.getDepth(); int type; Loading @@ -493,7 +519,7 @@ class ShortcutPackage extends ShortcutPackageItem { if (depth == outerDepth + 1) { switch (tag) { case ShortcutPackageInfo.TAG_ROOT: spi = ShortcutPackageInfo.loadFromXml(parser); ret.getPackageInfo().loadFromXml(parser, fromBackup); continue; case TAG_SHORTCUT: final ShortcutInfo si = parseShortcut(parser, packageName); Loading @@ -505,9 +531,6 @@ class ShortcutPackage extends ShortcutPackageItem { } ShortcutService.warnForInvalidTag(depth, tag); } if (spi != null) { ret.replacePackageInfo(spi); } return ret; } Loading Loading @@ -567,4 +590,9 @@ class ShortcutPackage extends ShortcutPackageItem { intentPersistableExtras, weight, extras, lastChangedTimestamp, flags, iconRes, bitmapPath); } @VisibleForTesting List<ShortcutInfo> getAllShortcutsForTest() { return new ArrayList<>(mShortcuts.values()); } } services/core/java/com/android/server/pm/ShortcutPackageInfo.java +28 −11 Original line number Diff line number Diff line Loading @@ -67,10 +67,6 @@ class ShortcutPackageInfo { return mIsShadow; } public boolean isInstalled() { return !mIsShadow; } public void setShadow(boolean shadow) { mIsShadow = shadow; } Loading @@ -79,14 +75,24 @@ class ShortcutPackageInfo { return mVersionCode; } public boolean canRestoreTo(PackageInfo target) { public boolean hasSignatures() { return mSigHashes.size() > 0; } public boolean canRestoreTo(ShortcutService s, PackageInfo target) { if (!s.shouldBackupApp(target)) { // "allowBackup" was true when backed up, but now false. Slog.w(TAG, "Can't restore: package no longer allows backup"); return false; } if (target.versionCode < mVersionCode) { Slog.w(TAG, String.format("Package current version %d < backed up version %d", Slog.w(TAG, String.format( "Can't restore: package current version %d < backed up version %d", target.versionCode, mVersionCode)); return false; } if (!BackupUtils.signaturesMatch(mSigHashes, target)) { Slog.w(TAG, "Package signature mismtach"); Slog.w(TAG, "Can't restore: Package signature mismatch"); return false; } return true; Loading @@ -106,6 +112,11 @@ class ShortcutPackageInfo { } public void refresh(ShortcutService s, ShortcutPackageItem pkg) { if (mIsShadow) { s.wtf("Attempted to refresh package info for shadow package " + pkg.getPackageName() + ", user=" + pkg.getOwnerUserId()); return; } // Note use mUserId here, rather than userId. final PackageInfo pi = s.getPackageInfoWithSignatures( pkg.getPackageName(), pkg.getPackageUserId()); Loading @@ -132,14 +143,16 @@ class ShortcutPackageInfo { out.endTag(null, TAG_ROOT); } public static ShortcutPackageInfo loadFromXml(XmlPullParser parser) public void loadFromXml(XmlPullParser parser, boolean fromBackup) throws IOException, XmlPullParserException { final int versionCode = ShortcutService.parseIntAttribute(parser, ATTR_VERSION); final boolean shadow = ShortcutService.parseBooleanAttribute(parser, ATTR_SHADOW); final ArrayList<byte[]> hashes = new ArrayList<>(); // When restoring from backup, it's always shadow. final boolean shadow = fromBackup || ShortcutService.parseBooleanAttribute(parser, ATTR_SHADOW); final ArrayList<byte[]> hashes = new ArrayList<>(); final int outerDepth = parser.getDepth(); int type; Loading @@ -163,7 +176,11 @@ class ShortcutPackageInfo { } ShortcutService.warnForInvalidTag(depth, tag); } return new ShortcutPackageInfo(versionCode, hashes, shadow); // Successfully loaded; replace the feilds. mVersionCode = versionCode; mIsShadow = shadow; mSigHashes = hashes; } public void dump(ShortcutService s, PrintWriter pw, String prefix) { Loading Loading
services/core/java/com/android/server/pm/ShortcutBackupAgent.java→core/java/com/android/server/backup/ShortcutBackupHelper.java +70 −0 Original line number Diff line number Diff line Loading @@ -13,25 +13,58 @@ * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.pm; package com.android.server.backup; import android.app.backup.BlobBackupHelper; import android.content.Context; import android.content.pm.IShortcutService; import android.os.ServiceManager; import android.os.UserHandle; import android.util.Slog; public class ShortcutBackupAgent extends BlobBackupHelper { public class ShortcutBackupHelper extends BlobBackupHelper { private static final String TAG = "ShortcutBackupAgent"; private static final int BLOB_VERSION = 1; public ShortcutBackupAgent(int currentBlobVersion, String... keys) { super(currentBlobVersion, keys); private static final String KEY_USER_FILE = "shortcutuser.xml"; public ShortcutBackupHelper() { super(BLOB_VERSION, KEY_USER_FILE); } private IShortcutService getShortcutService() { return IShortcutService.Stub.asInterface( ServiceManager.getService(Context.SHORTCUT_SERVICE)); } @Override protected byte[] getBackupPayload(String key) { throw new RuntimeException("not implemented yet"); // todo switch (key) { case KEY_USER_FILE: try { return getShortcutService().getBackupPayload(UserHandle.USER_SYSTEM); } catch (Exception e) { Slog.wtf(TAG, "Backup failed", e); } break; default: Slog.w(TAG, "Unknown key: " + key); } return null; } @Override protected void applyRestoredPayload(String key, byte[] payload) { throw new RuntimeException("not implemented yet"); // todo switch (key) { case KEY_USER_FILE: try { getShortcutService().applyRestore(payload, UserHandle.USER_SYSTEM); } catch (Exception e) { Slog.wtf(TAG, "Restore failed", e); } break; default: Slog.w(TAG, "Unknown key: " + key); } } }
core/java/com/android/server/backup/SystemBackupAgent.java +4 −1 Original line number Diff line number Diff line Loading @@ -17,9 +17,9 @@ package com.android.server.backup; import android.app.IWallpaperManager; import android.app.backup.BackupAgentHelper; import android.app.backup.BackupDataInput; import android.app.backup.BackupDataOutput; import android.app.backup.BackupAgentHelper; import android.app.backup.FullBackup; import android.app.backup.FullBackupDataOutput; import android.app.backup.WallpaperBackupHelper; Loading Loading @@ -48,6 +48,7 @@ public class SystemBackupAgent extends BackupAgentHelper { private static final String NOTIFICATION_HELPER = "notifications"; private static final String PERMISSION_HELPER = "permissions"; private static final String USAGE_STATS_HELPER = "usage_stats"; private static final String SHORTCUT_MANAGER_HELPER = "shortcut_manager"; // These paths must match what the WallpaperManagerService uses. The leaf *_FILENAME // are also used in the full-backup file format, so must not change unless steps are Loading Loading @@ -100,6 +101,7 @@ public class SystemBackupAgent extends BackupAgentHelper { addHelper(NOTIFICATION_HELPER, new NotificationBackupHelper(this)); addHelper(PERMISSION_HELPER, new PermissionBackupHelper()); addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(this)); addHelper(SHORTCUT_MANAGER_HELPER, new ShortcutBackupHelper()); super.onBackup(oldState, data, newState); } Loading Loading @@ -138,6 +140,7 @@ public class SystemBackupAgent extends BackupAgentHelper { addHelper(NOTIFICATION_HELPER, new NotificationBackupHelper(this)); addHelper(PERMISSION_HELPER, new PermissionBackupHelper()); addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(this)); addHelper(SHORTCUT_MANAGER_HELPER, new ShortcutBackupHelper()); try { super.onRestore(data, appVersionCode, newState); Loading
services/core/java/com/android/server/pm/ShortcutLauncher.java +70 −22 Original line number Diff line number Diff line Loading @@ -20,6 +20,10 @@ import android.annotation.UserIdInt; import android.content.pm.ShortcutInfo; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.server.pm.ShortcutUser.PackageWithUser; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; Loading @@ -27,6 +31,7 @@ import org.xmlpull.v1.XmlSerializer; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; /** Loading @@ -43,15 +48,16 @@ class ShortcutLauncher extends ShortcutPackageItem { private static final String ATTR_LAUNCHER_USER_ID = "launcher-user"; private static final String ATTR_VALUE = "value"; private static final String ATTR_PACKAGE_NAME = "package-name"; private static final String ATTR_PACKAGE_USER_ID = "package-user"; private final int mOwnerUserId; /** * Package name -> IDs. */ final private ArrayMap<String, ArraySet<String>> mPinnedShortcuts = new ArrayMap<>(); final private ArrayMap<PackageWithUser, ArraySet<String>> mPinnedShortcuts = new ArrayMap<>(); public ShortcutLauncher(@UserIdInt int ownerUserId, @NonNull String packageName, private ShortcutLauncher(@UserIdInt int ownerUserId, @NonNull String packageName, @UserIdInt int launcherUserId, ShortcutPackageInfo spi) { super(launcherUserId, packageName, spi != null ? spi : ShortcutPackageInfo.newEmpty()); mOwnerUserId = ownerUserId; Loading @@ -59,7 +65,7 @@ class ShortcutLauncher extends ShortcutPackageItem { public ShortcutLauncher(@UserIdInt int ownerUserId, @NonNull String packageName, @UserIdInt int launcherUserId) { this(launcherUserId, packageName, launcherUserId, null); this(ownerUserId, packageName, launcherUserId, null); } @Override Loading @@ -67,16 +73,38 @@ class ShortcutLauncher extends ShortcutPackageItem { return mOwnerUserId; } /** * Called when the new package can't receive the backup, due to signature or version mismatch. */ @Override protected void onRestoreBlocked(ShortcutService s) { final ArrayList<PackageWithUser> pinnedPackages = new ArrayList<>(mPinnedShortcuts.keySet()); mPinnedShortcuts.clear(); for (int i = pinnedPackages.size() - 1; i >= 0; i--) { final PackageWithUser pu = pinnedPackages.get(i); s.getPackageShortcutsLocked(pu.packageName, pu.userId) .refreshPinnedFlags(s); } } @Override protected void onRestored(ShortcutService s) { // Nothing to do. } public void pinShortcuts(@NonNull ShortcutService s, @UserIdInt int packageUserId, @NonNull String packageName, @NonNull List<String> ids) { final ShortcutPackage packageShortcuts = s.getPackageShortcutsLocked(packageName, packageUserId); final PackageWithUser pu = PackageWithUser.of(packageUserId, packageName); final int idSize = ids.size(); if (idSize == 0) { mPinnedShortcuts.remove(packageName); mPinnedShortcuts.remove(pu); } else { final ArraySet<String> prevSet = mPinnedShortcuts.get(packageName); final ArraySet<String> prevSet = mPinnedShortcuts.get(pu); // Pin shortcuts. Make sure only pin the ones that were visible to the caller. // i.e. a non-dynamic, pinned shortcut by *other launchers* shouldn't be pinned here. Loading @@ -93,7 +121,7 @@ class ShortcutLauncher extends ShortcutPackageItem { newSet.add(id); } } mPinnedShortcuts.put(packageName, newSet); mPinnedShortcuts.put(pu, newSet); } packageShortcuts.refreshPinnedFlags(s); } Loading @@ -101,12 +129,13 @@ class ShortcutLauncher extends ShortcutPackageItem { /** * Return the pinned shortcut IDs for the publisher package. */ public ArraySet<String> getPinnedShortcutIds(@NonNull String packageName) { return mPinnedShortcuts.get(packageName); public ArraySet<String> getPinnedShortcutIds(@NonNull String packageName, @UserIdInt int packageUserId) { return mPinnedShortcuts.get(PackageWithUser.of(packageUserId, packageName)); } boolean cleanUpPackage(String packageName) { return mPinnedShortcuts.remove(packageName) != null; boolean cleanUpPackage(String packageName, @UserIdInt int packageUserId) { return mPinnedShortcuts.remove(PackageWithUser.of(packageUserId, packageName)) != null; } /** Loading @@ -126,9 +155,15 @@ class ShortcutLauncher extends ShortcutPackageItem { getPackageInfo().saveToXml(out); for (int i = 0; i < size; i++) { final PackageWithUser pu = mPinnedShortcuts.keyAt(i); if (forBackup && (pu.userId != getOwnerUserId())) { continue; // Target package on a different user, skip. (i.e. work profile) } out.startTag(null, TAG_PACKAGE); ShortcutService.writeAttr(out, ATTR_PACKAGE_NAME, mPinnedShortcuts.keyAt(i)); ShortcutService.writeAttr(out, ATTR_PACKAGE_NAME, pu.packageName); ShortcutService.writeAttr(out, ATTR_PACKAGE_USER_ID, pu.userId); final ArraySet<String> ids = mPinnedShortcuts.valueAt(i); final int idSize = ids.size(); Loading Loading @@ -157,8 +192,6 @@ class ShortcutLauncher extends ShortcutPackageItem { final ShortcutLauncher ret = new ShortcutLauncher(launcherUserId, launcherPackageName, launcherUserId); ShortcutPackageInfo spi = null; ArraySet<String> ids = null; final int outerDepth = parser.getDepth(); int type; Loading @@ -172,13 +205,17 @@ class ShortcutLauncher extends ShortcutPackageItem { if (depth == outerDepth + 1) { switch (tag) { case ShortcutPackageInfo.TAG_ROOT: spi = ShortcutPackageInfo.loadFromXml(parser); ret.getPackageInfo().loadFromXml(parser, fromBackup); continue; case TAG_PACKAGE: { final String packageName = ShortcutService.parseStringAttribute(parser, ATTR_PACKAGE_NAME); final int packageUserId = fromBackup ? ownerUserId : ShortcutService.parseIntAttribute(parser, ATTR_PACKAGE_USER_ID, ownerUserId); ids = new ArraySet<>(); ret.mPinnedShortcuts.put(packageName, ids); ret.mPinnedShortcuts.put( PackageWithUser.of(packageUserId, packageName), ids); continue; } } Loading @@ -186,17 +223,17 @@ class ShortcutLauncher extends ShortcutPackageItem { if (depth == outerDepth + 2) { switch (tag) { case TAG_PIN: { ids.add(ShortcutService.parseStringAttribute(parser, ATTR_VALUE)); if (ids == null) { Slog.w(TAG, TAG_PIN + " in invalid place"); } else { ids.add(ShortcutService.parseStringAttribute(parser, ATTR_VALUE)); } continue; } } } ShortcutService.warnForInvalidTag(depth, tag); } if (spi != null) { ret.replacePackageInfo(spi); } return ret; } Loading @@ -208,6 +245,8 @@ class ShortcutLauncher extends ShortcutPackageItem { pw.print(getPackageName()); pw.print(" Package user: "); pw.print(getPackageUserId()); pw.print(" Owner user: "); pw.print(getOwnerUserId()); pw.println(); getPackageInfo().dump(s, pw, prefix + " "); Loading @@ -217,10 +256,14 @@ class ShortcutLauncher extends ShortcutPackageItem { for (int i = 0; i < size; i++) { pw.println(); final PackageWithUser pu = mPinnedShortcuts.keyAt(i); pw.print(prefix); pw.print(" "); pw.print("Package: "); pw.println(mPinnedShortcuts.keyAt(i)); pw.print(pu.packageName); pw.print(" User: "); pw.println(pu.userId); final ArraySet<String> ids = mPinnedShortcuts.valueAt(i); final int idSize = ids.size(); Loading @@ -233,4 +276,9 @@ class ShortcutLauncher extends ShortcutPackageItem { } } } @VisibleForTesting ArraySet<String> getAllPinnedShortcutsForTest(String packageName, int packageUserId) { return new ArraySet<>(mPinnedShortcuts.get(PackageWithUser.of(packageUserId, packageName))); } }
services/core/java/com/android/server/pm/ShortcutPackage.java +42 −14 Original line number Diff line number Diff line Loading @@ -26,6 +26,8 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; Loading @@ -34,6 +36,7 @@ import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.function.Predicate; Loading Loading @@ -83,7 +86,7 @@ class ShortcutPackage extends ShortcutPackageItem { */ private long mLastResetTime; public ShortcutPackage(int packageUserId, String packageName, ShortcutPackageInfo spi) { private ShortcutPackage(int packageUserId, String packageName, ShortcutPackageInfo spi) { super(packageUserId, packageName, spi != null ? spi : ShortcutPackageInfo.newEmpty()); } Loading @@ -97,6 +100,19 @@ class ShortcutPackage extends ShortcutPackageItem { return getPackageUserId(); } @Override protected void onRestoreBlocked(ShortcutService s) { // Can't restore due to version/signature mismatch. Remove all shortcuts. mShortcuts.clear(); } @Override protected void onRestored(ShortcutService s) { // Because some launchers may not have been restored (e.g. allowBackup=false), // we need to re-calculate the pinned shortcuts. refreshPinnedFlags(s); } /** * Note this does *not* provide a correct view to the calling launcher. */ Loading Loading @@ -229,20 +245,26 @@ class ShortcutPackage extends ShortcutPackageItem { s.getUserShortcutsLocked(getPackageUserId()).getAllLaunchers(); for (int l = launchers.size() - 1; l >= 0; l--) { // Note even if a launcher that hasn't been installed can still pin shortcuts. final ShortcutLauncher launcherShortcuts = launchers.valueAt(l); final ArraySet<String> pinned = launcherShortcuts.getPinnedShortcutIds( getPackageName()); getPackageName(), getPackageUserId()); if (pinned == null || pinned.size() == 0) { continue; } for (int i = pinned.size() - 1; i >= 0; i--) { final ShortcutInfo si = mShortcuts.get(pinned.valueAt(i)); final String id = pinned.valueAt(i); final ShortcutInfo si = mShortcuts.get(id); if (si == null) { s.wtf("Shortcut not found"); } else { si.addFlags(ShortcutInfo.FLAG_PINNED); // This happens if a launcher pinned shortcuts from this package, then backup& // restored, but this package doesn't allow backing up. // In that case the launcher ends up having a dangling pinned shortcuts. // That's fine, when the launcher is restored, we'll fix it. continue; } si.addFlags(ShortcutInfo.FLAG_PINNED); } } Loading Loading @@ -312,11 +334,15 @@ class ShortcutPackage extends ShortcutPackageItem { public void findAll(@NonNull ShortcutService s, @NonNull List<ShortcutInfo> result, @Nullable Predicate<ShortcutInfo> query, int cloneFlag, @Nullable String callingLauncher, int launcherUserId) { if (getPackageInfo().isShadow()) { // Restored and the app not installed yet, so don't return any. return; } // Set of pinned shortcuts by the calling launcher. final ArraySet<String> pinnedByCallerSet = (callingLauncher == null) ? null : s.getLauncherShortcuts(callingLauncher, getPackageUserId(), launcherUserId) .getPinnedShortcutIds(getPackageName()); : s.getLauncherShortcutsLocked(callingLauncher, getPackageUserId(), launcherUserId) .getPinnedShortcutIds(getPackageName(), getPackageUserId()); for (int i = 0; i < mShortcuts.size(); i++) { final ShortcutInfo si = mShortcuts.valueAt(i); Loading @@ -328,7 +354,8 @@ class ShortcutPackage extends ShortcutPackageItem { || ((pinnedByCallerSet != null) && pinnedByCallerSet.contains(si.getId())); if (!si.isDynamic()) { if (!si.isPinned()) { s.wtf("Shortcut not pinned here"); s.wtf("Shortcut not pinned: package " + getPackageName() + ", user=" + getPackageUserId() + ", id=" + si.getId()); continue; } if (!isPinnedByCaller) { Loading Loading @@ -479,7 +506,6 @@ class ShortcutPackage extends ShortcutPackageItem { ShortcutService.parseIntAttribute(parser, ATTR_CALL_COUNT); ret.mLastResetTime = ShortcutService.parseLongAttribute(parser, ATTR_LAST_RESET); ShortcutPackageInfo spi = null; final int outerDepth = parser.getDepth(); int type; Loading @@ -493,7 +519,7 @@ class ShortcutPackage extends ShortcutPackageItem { if (depth == outerDepth + 1) { switch (tag) { case ShortcutPackageInfo.TAG_ROOT: spi = ShortcutPackageInfo.loadFromXml(parser); ret.getPackageInfo().loadFromXml(parser, fromBackup); continue; case TAG_SHORTCUT: final ShortcutInfo si = parseShortcut(parser, packageName); Loading @@ -505,9 +531,6 @@ class ShortcutPackage extends ShortcutPackageItem { } ShortcutService.warnForInvalidTag(depth, tag); } if (spi != null) { ret.replacePackageInfo(spi); } return ret; } Loading Loading @@ -567,4 +590,9 @@ class ShortcutPackage extends ShortcutPackageItem { intentPersistableExtras, weight, extras, lastChangedTimestamp, flags, iconRes, bitmapPath); } @VisibleForTesting List<ShortcutInfo> getAllShortcutsForTest() { return new ArrayList<>(mShortcuts.values()); } }
services/core/java/com/android/server/pm/ShortcutPackageInfo.java +28 −11 Original line number Diff line number Diff line Loading @@ -67,10 +67,6 @@ class ShortcutPackageInfo { return mIsShadow; } public boolean isInstalled() { return !mIsShadow; } public void setShadow(boolean shadow) { mIsShadow = shadow; } Loading @@ -79,14 +75,24 @@ class ShortcutPackageInfo { return mVersionCode; } public boolean canRestoreTo(PackageInfo target) { public boolean hasSignatures() { return mSigHashes.size() > 0; } public boolean canRestoreTo(ShortcutService s, PackageInfo target) { if (!s.shouldBackupApp(target)) { // "allowBackup" was true when backed up, but now false. Slog.w(TAG, "Can't restore: package no longer allows backup"); return false; } if (target.versionCode < mVersionCode) { Slog.w(TAG, String.format("Package current version %d < backed up version %d", Slog.w(TAG, String.format( "Can't restore: package current version %d < backed up version %d", target.versionCode, mVersionCode)); return false; } if (!BackupUtils.signaturesMatch(mSigHashes, target)) { Slog.w(TAG, "Package signature mismtach"); Slog.w(TAG, "Can't restore: Package signature mismatch"); return false; } return true; Loading @@ -106,6 +112,11 @@ class ShortcutPackageInfo { } public void refresh(ShortcutService s, ShortcutPackageItem pkg) { if (mIsShadow) { s.wtf("Attempted to refresh package info for shadow package " + pkg.getPackageName() + ", user=" + pkg.getOwnerUserId()); return; } // Note use mUserId here, rather than userId. final PackageInfo pi = s.getPackageInfoWithSignatures( pkg.getPackageName(), pkg.getPackageUserId()); Loading @@ -132,14 +143,16 @@ class ShortcutPackageInfo { out.endTag(null, TAG_ROOT); } public static ShortcutPackageInfo loadFromXml(XmlPullParser parser) public void loadFromXml(XmlPullParser parser, boolean fromBackup) throws IOException, XmlPullParserException { final int versionCode = ShortcutService.parseIntAttribute(parser, ATTR_VERSION); final boolean shadow = ShortcutService.parseBooleanAttribute(parser, ATTR_SHADOW); final ArrayList<byte[]> hashes = new ArrayList<>(); // When restoring from backup, it's always shadow. final boolean shadow = fromBackup || ShortcutService.parseBooleanAttribute(parser, ATTR_SHADOW); final ArrayList<byte[]> hashes = new ArrayList<>(); final int outerDepth = parser.getDepth(); int type; Loading @@ -163,7 +176,11 @@ class ShortcutPackageInfo { } ShortcutService.warnForInvalidTag(depth, tag); } return new ShortcutPackageInfo(versionCode, hashes, shadow); // Successfully loaded; replace the feilds. mVersionCode = versionCode; mIsShadow = shadow; mSigHashes = hashes; } public void dump(ShortcutService s, PrintWriter pw, String prefix) { Loading