Merge "Properly protect ShortcutPackage#mShortcuts with synchronization lock." into tm-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
645f51d337
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user