Merge "Properly protect ShortcutPackage#mShortcuts with synchronization lock." into tm-dev

This commit is contained in:
TreeHugger Robot
2022-05-06 22:57:07 +00:00
committed by Android (Google) Code Review

View File

@@ -166,18 +166,19 @@ class ShortcutPackage extends ShortcutPackageItem {
* An in-memory copy of shortcuts for this package that was loaded from xml, keyed on IDs. * An in-memory copy of shortcuts for this package that was loaded from xml, keyed on IDs.
*/ */
@GuardedBy("mLock") @GuardedBy("mLock")
final ArrayMap<String, ShortcutInfo> mShortcuts = new ArrayMap<>(); private final ArrayMap<String, ShortcutInfo> mShortcuts = new ArrayMap<>();
/** /**
* A temporary copy of shortcuts that are to be cleared once persisted into AppSearch, keyed on * A temporary copy of shortcuts that are to be cleared once persisted into AppSearch, keyed on
* IDs. * IDs.
*/ */
@GuardedBy("mLock") @GuardedBy("mLock")
private ArrayMap<String, ShortcutInfo> mTransientShortcuts = new ArrayMap<>(0); private final ArrayMap<String, ShortcutInfo> mTransientShortcuts = new ArrayMap<>(0);
/** /**
* All the share targets from the package * All the share targets from the package
*/ */
@GuardedBy("mLock")
private final ArrayList<ShareTargetInfo> mShareTargets = new ArrayList<>(0); private final ArrayList<ShareTargetInfo> mShareTargets = new ArrayList<>(0);
/** /**
@@ -231,8 +232,10 @@ class ShortcutPackage extends ShortcutPackageItem {
} }
public int getShortcutCount() { public int getShortcutCount() {
synchronized (mLock) {
return mShortcuts.size(); return mShortcuts.size();
} }
}
@Override @Override
protected boolean canRestoreAnyVersion() { protected boolean canRestoreAnyVersion() {
@@ -272,8 +275,10 @@ class ShortcutPackage extends ShortcutPackageItem {
@Nullable @Nullable
public ShortcutInfo findShortcutById(@Nullable final String id) { public ShortcutInfo findShortcutById(@Nullable final String id) {
if (id == null) return null; if (id == null) return null;
synchronized (mLock) {
return mShortcuts.get(id); return mShortcuts.get(id);
} }
}
public boolean isShortcutExistsAndInvisibleToPublisher(String id) { public boolean isShortcutExistsAndInvisibleToPublisher(String id) {
ShortcutInfo si = findShortcutById(id); ShortcutInfo si = findShortcutById(id);
@@ -347,12 +352,15 @@ class ShortcutPackage extends ShortcutPackageItem {
* Delete a shortcut by ID. This will *always* remove it even if it's immutable or invisible. * Delete a shortcut by ID. This will *always* remove it even if it's immutable or invisible.
*/ */
private ShortcutInfo forceDeleteShortcutInner(@NonNull String id) { private ShortcutInfo forceDeleteShortcutInner(@NonNull String id) {
final ShortcutInfo shortcut = mShortcuts.remove(id); final ShortcutInfo shortcut;
synchronized (mLock) {
shortcut = mShortcuts.remove(id);
if (shortcut != null) { if (shortcut != null) {
removeIcon(shortcut); removeIcon(shortcut);
shortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_PINNED shortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_PINNED
| ShortcutInfo.FLAG_MANIFEST | ShortcutInfo.FLAG_CACHED_ALL); | ShortcutInfo.FLAG_MANIFEST | ShortcutInfo.FLAG_CACHED_ALL);
} }
}
return shortcut; return shortcut;
} }
@@ -524,6 +532,7 @@ class ShortcutPackage extends ShortcutPackageItem {
public List<ShortcutInfo> deleteAllDynamicShortcuts() { public List<ShortcutInfo> deleteAllDynamicShortcuts() {
final long now = mShortcutUser.mService.injectCurrentTimeMillis(); final long now = mShortcutUser.mService.injectCurrentTimeMillis();
boolean changed = false; boolean changed = false;
synchronized (mLock) {
for (int i = mShortcuts.size() - 1; i >= 0; i--) { for (int i = mShortcuts.size() - 1; i >= 0; i--) {
ShortcutInfo si = mShortcuts.valueAt(i); ShortcutInfo si = mShortcuts.valueAt(i);
if (si.isDynamic() && si.isVisibleToPublisher()) { if (si.isDynamic() && si.isVisibleToPublisher()) {
@@ -534,6 +543,7 @@ class ShortcutPackage extends ShortcutPackageItem {
si.setRank(0); // It may still be pinned, so clear the rank. si.setRank(0); // It may still be pinned, so clear the rank.
} }
} }
}
removeAllShortcutsAsync(); removeAllShortcutsAsync();
if (changed) { if (changed) {
return removeOrphans(); return removeOrphans();
@@ -874,6 +884,7 @@ class ShortcutPackage extends ShortcutPackageItem {
*/ */
public List<ShortcutManager.ShareShortcutInfo> getMatchingShareTargets( public List<ShortcutManager.ShareShortcutInfo> getMatchingShareTargets(
@NonNull IntentFilter filter) { @NonNull IntentFilter filter) {
synchronized (mLock) {
final List<ShareTargetInfo> matchedTargets = new ArrayList<>(); final List<ShareTargetInfo> matchedTargets = new ArrayList<>();
for (int i = 0; i < mShareTargets.size(); i++) { for (int i = 0; i < mShareTargets.size(); i++) {
final ShareTargetInfo target = mShareTargets.get(i); final ShareTargetInfo target = mShareTargets.get(i);
@@ -924,10 +935,13 @@ class ShortcutPackage extends ShortcutPackageItem {
} }
return result; return result;
} }
}
public boolean hasShareTargets() { public boolean hasShareTargets() {
synchronized (mLock) {
return !mShareTargets.isEmpty(); return !mShareTargets.isEmpty();
} }
}
/** /**
* Returns the number of shortcuts that can be used as a share target in the ShareSheet. Such * Returns the number of shortcuts that can be used as a share target in the ShareSheet. Such
@@ -935,6 +949,7 @@ class ShortcutPackage extends ShortcutPackageItem {
* the app's Xml resource. * the app's Xml resource.
*/ */
int getSharingShortcutCount() { int getSharingShortcutCount() {
synchronized (mLock) {
if (mShareTargets.isEmpty()) { if (mShareTargets.isEmpty()) {
return 0; return 0;
} }
@@ -968,6 +983,7 @@ class ShortcutPackage extends ShortcutPackageItem {
} }
return sharingShortcutCount; return sharingShortcutCount;
} }
}
/** /**
* Return the filenames (excluding path names) of icon bitmap files from this package. * Return the filenames (excluding path names) of icon bitmap files from this package.
@@ -1090,19 +1106,25 @@ class ShortcutPackage extends ShortcutPackageItem {
// Now prepare to publish manifest shortcuts. // Now prepare to publish manifest shortcuts.
List<ShortcutInfo> newManifestShortcutList = null; List<ShortcutInfo> newManifestShortcutList = null;
final int shareTargetSize;
synchronized (mLock) {
try { try {
shareTargetSize = mShareTargets.size();
newManifestShortcutList = ShortcutParser.parseShortcuts(mShortcutUser.mService, newManifestShortcutList = ShortcutParser.parseShortcuts(mShortcutUser.mService,
getPackageName(), getPackageUserId(), mShareTargets); getPackageName(), getPackageUserId(), mShareTargets);
} catch (IOException|XmlPullParserException e) { } catch (IOException | XmlPullParserException e) {
Slog.e(TAG, "Failed to load shortcuts from AndroidManifest.xml.", e); Slog.e(TAG, "Failed to load shortcuts from AndroidManifest.xml.", e);
} }
}
final int manifestShortcutSize = newManifestShortcutList == null ? 0 final int manifestShortcutSize = newManifestShortcutList == null ? 0
: newManifestShortcutList.size(); : newManifestShortcutList.size();
if (ShortcutService.DEBUG || ShortcutService.DEBUG_REBOOT) { if (ShortcutService.DEBUG || ShortcutService.DEBUG_REBOOT) {
Slog.d(TAG, Slog.d(TAG,
String.format("Package %s has %d manifest shortcut(s), and %d share target(s)", String.format(
getPackageName(), manifestShortcutSize, mShareTargets.size())); "Package %s has %d manifest shortcut(s), and %d share target(s)",
getPackageName(), manifestShortcutSize, shareTargetSize));
} }
if (isNewApp && (manifestShortcutSize == 0)) { if (isNewApp && (manifestShortcutSize == 0)) {
// If it's a new app, and it doesn't have manifest shortcuts, then nothing to do. // If it's a new app, and it doesn't have manifest shortcuts, then nothing to do.
@@ -1701,6 +1723,7 @@ class ShortcutPackage extends ShortcutPackageItem {
@Override @Override
public void saveToXml(@NonNull TypedXmlSerializer out, boolean forBackup) public void saveToXml(@NonNull TypedXmlSerializer out, boolean forBackup)
throws IOException, XmlPullParserException { throws IOException, XmlPullParserException {
synchronized (mLock) {
final int size = mShortcuts.size(); final int size = mShortcuts.size();
final int shareTargetSize = mShareTargets.size(); final int shareTargetSize = mShareTargets.size();
@@ -1714,15 +1737,14 @@ class ShortcutPackage extends ShortcutPackageItem {
ShortcutService.writeAttr(out, ATTR_CALL_COUNT, mApiCallCount); ShortcutService.writeAttr(out, ATTR_CALL_COUNT, mApiCallCount);
ShortcutService.writeAttr(out, ATTR_LAST_RESET, mLastResetTime); ShortcutService.writeAttr(out, ATTR_LAST_RESET, mLastResetTime);
if (!forBackup) { if (!forBackup) {
synchronized (mLock) { ShortcutService.writeAttr(out, ATTR_SCHEMA_VERSON, mIsAppSearchSchemaUpToDate
ShortcutService.writeAttr(out, ATTR_SCHEMA_VERSON, (mIsAppSearchSchemaUpToDate)
? AppSearchShortcutInfo.SCHEMA_VERSION : 0); ? AppSearchShortcutInfo.SCHEMA_VERSION : 0);
} }
}
getPackageInfo().saveToXml(mShortcutUser.mService, out, forBackup); getPackageInfo().saveToXml(mShortcutUser.mService, out, forBackup);
for (int j = 0; j < size; j++) { for (int j = 0; j < size; j++) {
saveShortcut(out, mShortcuts.valueAt(j), forBackup, getPackageInfo().isBackupAllowed()); saveShortcut(
out, mShortcuts.valueAt(j), forBackup, getPackageInfo().isBackupAllowed());
} }
if (!forBackup) { if (!forBackup) {
@@ -1733,6 +1755,7 @@ class ShortcutPackage extends ShortcutPackageItem {
out.endTag(null, TAG_ROOT); out.endTag(null, TAG_ROOT);
} }
}
private void saveShortcut(TypedXmlSerializer out, ShortcutInfo si, boolean forBackup, private void saveShortcut(TypedXmlSerializer out, ShortcutInfo si, boolean forBackup,
boolean appSupportsBackup) boolean appSupportsBackup)
@@ -1917,11 +1940,10 @@ class ShortcutPackage extends ShortcutPackageItem {
synchronized (ret.mLock) { synchronized (ret.mLock) {
ret.mIsAppSearchSchemaUpToDate = ShortcutService.parseIntAttribute( ret.mIsAppSearchSchemaUpToDate = ShortcutService.parseIntAttribute(
parser, ATTR_SCHEMA_VERSON, 0) == AppSearchShortcutInfo.SCHEMA_VERSION; parser, ATTR_SCHEMA_VERSON, 0) == AppSearchShortcutInfo.SCHEMA_VERSION;
}
ret.mApiCallCount = ShortcutService.parseIntAttribute(parser, ATTR_CALL_COUNT); ret.mApiCallCount = ShortcutService.parseIntAttribute(parser, ATTR_CALL_COUNT);
ret.mLastResetTime = ShortcutService.parseLongAttribute(parser, ATTR_LAST_RESET); ret.mLastResetTime = ShortcutService.parseLongAttribute(parser, ATTR_LAST_RESET);
final int outerDepth = parser.getDepth(); final int outerDepth = parser.getDepth();
int type; int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -1950,6 +1972,7 @@ class ShortcutPackage extends ShortcutPackageItem {
} }
ShortcutService.warnForInvalidTag(depth, tag); ShortcutService.warnForInvalidTag(depth, tag);
} }
}
return ret; return ret;
} }
@@ -2152,8 +2175,10 @@ class ShortcutPackage extends ShortcutPackageItem {
@VisibleForTesting @VisibleForTesting
List<ShareTargetInfo> getAllShareTargetsForTest() { List<ShareTargetInfo> getAllShareTargetsForTest() {
synchronized (mLock) {
return new ArrayList<>(mShareTargets); return new ArrayList<>(mShareTargets);
} }
}
@Override @Override
public void verifyStates() { public void verifyStates() {
@@ -2291,16 +2316,20 @@ class ShortcutPackage extends ShortcutPackageItem {
private void saveShortcut(@NonNull final Collection<ShortcutInfo> shortcuts) { private void saveShortcut(@NonNull final Collection<ShortcutInfo> shortcuts) {
Objects.requireNonNull(shortcuts); Objects.requireNonNull(shortcuts);
synchronized (mLock) {
for (ShortcutInfo si : shortcuts) { for (ShortcutInfo si : shortcuts) {
mShortcuts.put(si.getId(), si); mShortcuts.put(si.getId(), si);
} }
} }
}
@Nullable @Nullable
List<ShortcutInfo> findAll(@NonNull final Collection<String> ids) { List<ShortcutInfo> findAll(@NonNull final Collection<String> ids) {
synchronized (mLock) {
return ids.stream().map(mShortcuts::get) return ids.stream().map(mShortcuts::get)
.filter(Objects::nonNull).collect(Collectors.toList()); .filter(Objects::nonNull).collect(Collectors.toList());
} }
}
private void forEachShortcut(@NonNull final Consumer<ShortcutInfo> cb) { private void forEachShortcut(@NonNull final Consumer<ShortcutInfo> cb) {
forEachShortcutStopWhen(si -> { forEachShortcutStopWhen(si -> {
@@ -2318,6 +2347,7 @@ class ShortcutPackage extends ShortcutPackageItem {
private void forEachShortcutStopWhen( private void forEachShortcutStopWhen(
@NonNull final Function<ShortcutInfo, Boolean> cb) { @NonNull final Function<ShortcutInfo, Boolean> cb) {
synchronized (mLock) {
for (int i = mShortcuts.size() - 1; i >= 0; i--) { for (int i = mShortcuts.size() - 1; i >= 0; i--) {
final ShortcutInfo si = mShortcuts.valueAt(i); final ShortcutInfo si = mShortcuts.valueAt(i);
if (cb.apply(si)) { if (cb.apply(si)) {
@@ -2325,6 +2355,7 @@ class ShortcutPackage extends ShortcutPackageItem {
} }
} }
} }
}
@NonNull @NonNull
private AndroidFuture<AppSearchSession> setupSchema( private AndroidFuture<AppSearchSession> setupSchema(
@@ -2461,6 +2492,7 @@ class ShortcutPackage extends ShortcutPackageItem {
}))); })));
} }
@GuardedBy("mLock")
@Override @Override
void scheduleSaveToAppSearchLocked() { void scheduleSaveToAppSearchLocked() {
final Map<String, ShortcutInfo> copy = new ArrayMap<>(mShortcuts); final Map<String, ShortcutInfo> copy = new ArrayMap<>(mShortcuts);