diff --git a/services/core/java/com/android/server/pm/DumpState.java b/services/core/java/com/android/server/pm/DumpState.java index ec79483e0f34b..ed00609cd8abb 100644 --- a/services/core/java/com/android/server/pm/DumpState.java +++ b/services/core/java/com/android/server/pm/DumpState.java @@ -58,6 +58,7 @@ public final class DumpState { private boolean mTitlePrinted; private boolean mFullPreferred; private boolean mCheckIn; + private boolean mBrief; private String mTargetPackageName; @@ -128,4 +129,12 @@ public final class DumpState { public void setCheckIn(boolean checkIn) { mCheckIn = checkIn; } + + public boolean isBrief() { + return mBrief; + } + + public void setBrief(boolean brief) { + mBrief = brief; + } } diff --git a/services/core/java/com/android/server/pm/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java index 2015c78e0817e..34caaf52b2154 100644 --- a/services/core/java/com/android/server/pm/KeySetManagerService.java +++ b/services/core/java/com/android/server/pm/KeySetManagerService.java @@ -30,6 +30,7 @@ import android.util.TypedXmlPullParser; import android.util.TypedXmlSerializer; import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.utils.WatchedArrayMap; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -65,7 +66,7 @@ public class KeySetManagerService { protected final LongSparseArray> mKeySetMapping; - private final ArrayMap mPackages; + private final WatchedArrayMap mPackages; private long lastIssuedKeySetId = 0; @@ -114,7 +115,7 @@ public class KeySetManagerService { } } - public KeySetManagerService(ArrayMap packages) { + public KeySetManagerService(WatchedArrayMap packages) { mKeySets = new LongSparseArray(); mPublicKeys = new LongSparseArray(); mKeySetMapping = new LongSparseArray>(); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 679042ff40c9d..882d8e64c8cc4 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -1309,14 +1309,17 @@ public class PackageManagerService extends IPackageManager.Stub // Avoid invalidation-thrashing by preventing cache invalidations from causing property // writes if the cache isn't enabled yet. We re-enable writes later when we're // done initializing. - sSnapshotCorked = true; + sSnapshotCorked.incrementAndGet(); PackageManager.corkPackageInfoCache(); } @Override public void enablePackageCaches() { // Uncork cache invalidations and allow clients to cache package information. - sSnapshotCorked = false; + int corking = sSnapshotCorked.decrementAndGet(); + if (TRACE_SNAPSHOTS && corking == 0) { + Log.i(TAG, "snapshot: corking returns to 0"); + } PackageManager.uncorkPackageInfoCache(); } } @@ -1588,6 +1591,7 @@ public class PackageManagerService extends IPackageManager.Stub static final int INTEGRITY_VERIFICATION_COMPLETE = 25; static final int CHECK_PENDING_INTEGRITY_VERIFICATION = 26; static final int DOMAIN_VERIFICATION = 27; + static final int SNAPSHOT_UNCORK = 28; static final int DEFERRED_NO_KILL_POST_DELETE_DELAY_MS = 3 * 1000; static final int DEFERRED_NO_KILL_INSTALL_OBSERVER_DELAY_MS = 500; @@ -4874,12 +4878,16 @@ public class PackageManagerService extends IPackageManager.Stub // A lock-free cache for frequently called functions. private volatile Computer mSnapshotComputer; // If true, the snapshot is invalid (stale). The attribute is static since it may be - // set from outside classes. - private static volatile boolean sSnapshotInvalid = true; + // set from outside classes. The attribute may be set to true anywhere, although it + // should only be set true while holding mLock. However, the attribute id guaranteed + // to be set false only while mLock and mSnapshotLock are both held. + private static AtomicBoolean sSnapshotInvalid = new AtomicBoolean(true); + // The package manager that is using snapshots. + private static PackageManagerService sSnapshotConsumer = null; // If true, the snapshot is corked. Do not create a new snapshot but use the live // computer. This throttles snapshot creation during periods of churn in Package // Manager. - private static volatile boolean sSnapshotCorked = false; + private static AtomicInteger sSnapshotCorked = new AtomicInteger(0); /** * This lock is used to make reads from {@link #sSnapshotInvalid} and @@ -4899,6 +4907,9 @@ public class PackageManagerService extends IPackageManager.Stub // and an image with the flag set false does not use snapshots. private static final boolean SNAPSHOT_ENABLED = false; + // The default auto-cork delay for snapshots. This is 1s. + private static final long SNAPSHOT_AUTOCORK_DELAY_MS = TimeUnit.SECONDS.toMillis(1); + // The per-instance snapshot disable/enable flag. This is generally set to false in // test instances and set to SNAPSHOT_ENABLED in operational instances. private final boolean mSnapshotEnabled; @@ -4922,15 +4933,16 @@ public class PackageManagerService extends IPackageManager.Stub // If the current thread holds mLock then it may have modified state but not // yet invalidated the snapshot. Always give the thread the live computer. return mLiveComputer; + } else if (sSnapshotCorked.get() > 0) { + // Snapshots are corked, which means new ones should not be built right now. + mSnapshotStatistics.corked(); + return mLiveComputer; } synchronized (mSnapshotLock) { + // This synchronization block serializes access to the snapshot computer and + // to the code that samples mSnapshotInvalid. Computer c = mSnapshotComputer; - if (sSnapshotCorked && (c != null)) { - // Snapshots are corked, which means new ones should not be built right now. - c.use(); - return c; - } - if (sSnapshotInvalid || (c == null)) { + if (sSnapshotInvalid.getAndSet(false) || (c == null)) { // The snapshot is invalid if it is marked as invalid or if it is null. If it // is null, then it is currently being rebuilt by rebuildSnapshot(). synchronized (mLock) { @@ -4938,9 +4950,7 @@ public class PackageManagerService extends IPackageManager.Stub // invalidated as it is rebuilt. However, the snapshot is still // self-consistent (the lock is being held) and is current as of the time // this function is entered. - if (sSnapshotInvalid) { - rebuildSnapshot(); - } + rebuildSnapshot(); // Guaranteed to be non-null. mSnapshotComputer is only be set to null // temporarily in rebuildSnapshot(), which is guarded by mLock(). Since @@ -4958,12 +4968,11 @@ public class PackageManagerService extends IPackageManager.Stub * Rebuild the cached computer. mSnapshotComputer is temporarily set to null to block other * threads from using the invalid computer until it is rebuilt. */ - @GuardedBy("mLock") + @GuardedBy({ "mLock", "mSnapshotLock"}) private void rebuildSnapshot() { final long now = SystemClock.currentTimeMicro(); final int hits = mSnapshotComputer == null ? -1 : mSnapshotComputer.getUsed(); mSnapshotComputer = null; - sSnapshotInvalid = false; final Snapshot args = new Snapshot(Snapshot.SNAPPED); mSnapshotComputer = new ComputerEngine(args); final long done = SystemClock.currentTimeMicro(); @@ -4971,6 +4980,30 @@ public class PackageManagerService extends IPackageManager.Stub mSnapshotStatistics.rebuild(now, done, hits); } + /** + * Create a new snapshot. Used for testing only. This does collect statistics or + * update the snapshot used by other actors. It does not alter the invalidation + * flag. This method takes the mLock internally. + */ + private Computer createNewSnapshot() { + synchronized (mLock) { + final Snapshot args = new Snapshot(Snapshot.SNAPPED); + return new ComputerEngine(args); + } + } + + /** + * Cork snapshots. This times out after the programmed delay. + */ + private void corkSnapshots(int multiplier) { + int corking = sSnapshotCorked.getAndIncrement(); + if (TRACE_SNAPSHOTS && corking == 0) { + Log.i(TAG, "snapshot: corking goes positive"); + } + Message message = mHandler.obtainMessage(SNAPSHOT_UNCORK); + mHandler.sendMessageDelayed(message, SNAPSHOT_AUTOCORK_DELAY_MS * multiplier); + } + /** * Create a live computer */ @@ -4986,9 +5019,9 @@ public class PackageManagerService extends IPackageManager.Stub */ public static void onChange(@Nullable Watchable what) { if (TRACE_SNAPSHOTS) { - Log.e(TAG, "snapshot: onChange(" + what + ")"); + Log.i(TAG, "snapshot: onChange(" + what + ")"); } - sSnapshotInvalid = true; + sSnapshotInvalid.set(true); } /** @@ -5367,6 +5400,13 @@ public class PackageManagerService extends IPackageManager.Stub mDomainVerificationManager.runMessage(messageCode, object); break; } + case SNAPSHOT_UNCORK: { + int corking = sSnapshotCorked.decrementAndGet(); + if (TRACE_SNAPSHOTS && corking == 0) { + Log.e(TAG, "snapshot: corking goes to zero in message handler"); + } + break; + } } } } @@ -6383,12 +6423,13 @@ public class PackageManagerService extends IPackageManager.Stub // constructor, at which time the invalidation method updates it. The cache is // corked initially to ensure a cached computer is not built until the end of the // constructor. - mSnapshotEnabled = SNAPSHOT_ENABLED; - sSnapshotCorked = true; - sSnapshotInvalid = true; mSnapshotStatistics = new SnapshotStatistics(); + sSnapshotConsumer = this; + sSnapshotCorked.set(1); + sSnapshotInvalid.set(true); mLiveComputer = createLiveComputer(); mSnapshotComputer = null; + mSnapshotEnabled = SNAPSHOT_ENABLED; registerObserver(); } @@ -18521,7 +18562,7 @@ public class PackageManagerService extends IPackageManager.Stub } } - @GuardedBy({"mInstallLock", "mLock"}) + @GuardedBy("mInstallLock") private void installPackagesTracedLI(List requests) { try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages"); @@ -24018,6 +24059,15 @@ public class PackageManagerService extends IPackageManager.Stub dumpState.setDump(DumpState.DUMP_PER_UID_READ_TIMEOUTS); } else if ("snapshot".equals(cmd)) { dumpState.setDump(DumpState.DUMP_SNAPSHOT_STATISTICS); + if (opti < args.length) { + if ("--full".equals(args[opti])) { + dumpState.setBrief(false); + opti++; + } else if ("--brief".equals(args[opti])) { + dumpState.setBrief(true); + opti++; + } + } } else if ("write".equals(cmd)) { synchronized (mLock) { writeSettingsLPrTEMP(); @@ -24353,13 +24403,14 @@ public class PackageManagerService extends IPackageManager.Stub pw.println(" Snapshots disabled"); } else { int hits = 0; + int level = sSnapshotCorked.get(); synchronized (mSnapshotLock) { if (mSnapshotComputer != null) { hits = mSnapshotComputer.getUsed(); } } final long now = SystemClock.currentTimeMicro(); - mSnapshotStatistics.dump(pw, " ", now, hits, true); + mSnapshotStatistics.dump(pw, " ", now, hits, level, dumpState.isBrief()); } } } diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 1b8eee3925a5f..e14c9871ea853 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -351,6 +351,7 @@ public final class Settings implements Watchable, Snappable { private final PackageManagerTracedLock mLock; + @Watched(manual = true) private final RuntimePermissionPersistence mRuntimePermissionsPersistence; private final File mSettingsFilename; @@ -435,6 +436,7 @@ public final class Settings implements Watchable, Snappable { } /** Device identity for the purpose of package verification. */ + @Watched(manual = true) private VerifierDeviceIdentity mVerifierDeviceIdentity; // The user's preferred activities associated with particular intent @@ -462,10 +464,12 @@ public final class Settings implements Watchable, Snappable { private final WatchedSparseArray mOtherAppIds; // For reading/writing settings file. - private final ArrayList mPastSignatures = - new ArrayList(); - private final ArrayMap mKeySetRefs = - new ArrayMap(); + @Watched + private final WatchedArrayList mPastSignatures = + new WatchedArrayList(); + @Watched + private final WatchedArrayMap mKeySetRefs = + new WatchedArrayMap(); // Packages that have been renamed since they were first installed. // Keys are the new names of the packages, values are the original @@ -495,18 +499,22 @@ public final class Settings implements Watchable, Snappable { * TODO: make this just a local variable that is passed in during package * scanning to make it less confusing. */ - private final ArrayList mPendingPackages = new ArrayList<>(); + @Watched + private final WatchedArrayList mPendingPackages = new WatchedArrayList<>(); private final File mSystemDir; - public final KeySetManagerService mKeySetManagerService = - new KeySetManagerService(mPackages.untrackedStorage()); + private final KeySetManagerService mKeySetManagerService = + new KeySetManagerService(mPackages); /** Settings and other information about permissions */ + @Watched(manual = true) final LegacyPermissionSettings mPermissions; + @Watched(manual = true) private final LegacyPermissionDataProvider mPermissionDataProvider; + @Watched(manual = true) private final DomainVerificationManagerInternal mDomainVerificationManager; /** @@ -532,6 +540,27 @@ public final class Settings implements Watchable, Snappable { }}; } + private void registerObservers() { + mPackages.registerObserver(mObserver); + mInstallerPackages.registerObserver(mObserver); + mKernelMapping.registerObserver(mObserver); + mDisabledSysPackages.registerObserver(mObserver); + mBlockUninstallPackages.registerObserver(mObserver); + mVersion.registerObserver(mObserver); + mPreferredActivities.registerObserver(mObserver); + mPersistentPreferredActivities.registerObserver(mObserver); + mCrossProfileIntentResolvers.registerObserver(mObserver); + mSharedUsers.registerObserver(mObserver); + mAppIds.registerObserver(mObserver); + mOtherAppIds.registerObserver(mObserver); + mRenamedPackages.registerObserver(mObserver); + mNextAppLinkGeneration.registerObserver(mObserver); + mDefaultBrowserApp.registerObserver(mObserver); + mPendingPackages.registerObserver(mObserver); + mPastSignatures.registerObserver(mObserver); + mKeySetRefs.registerObserver(mObserver); + } + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) public Settings(Map pkgSettings) { mLock = new PackageManagerTracedLock(); @@ -549,22 +578,8 @@ public final class Settings implements Watchable, Snappable { mBackupStoppedPackagesFilename = null; mKernelMappingFilename = null; mDomainVerificationManager = null; - mPackages.registerObserver(mObserver); - mInstallerPackages.registerObserver(mObserver); - mKernelMapping.registerObserver(mObserver); - mDisabledSysPackages.registerObserver(mObserver); - mBlockUninstallPackages.registerObserver(mObserver); - mVersion.registerObserver(mObserver); - mPreferredActivities.registerObserver(mObserver); - mPersistentPreferredActivities.registerObserver(mObserver); - mCrossProfileIntentResolvers.registerObserver(mObserver); - mSharedUsers.registerObserver(mObserver); - mAppIds.registerObserver(mObserver); - mOtherAppIds.registerObserver(mObserver); - mRenamedPackages.registerObserver(mObserver); - mNextAppLinkGeneration.registerObserver(mObserver); - mDefaultBrowserApp.registerObserver(mObserver); + registerObservers(); Watchable.verifyWatchedAttributes(this, mObserver); mSnapshot = makeCache(); @@ -602,22 +617,7 @@ public final class Settings implements Watchable, Snappable { mDomainVerificationManager = domainVerificationManager; - mPackages.registerObserver(mObserver); - mInstallerPackages.registerObserver(mObserver); - mKernelMapping.registerObserver(mObserver); - mDisabledSysPackages.registerObserver(mObserver); - mBlockUninstallPackages.registerObserver(mObserver); - mVersion.registerObserver(mObserver); - mPreferredActivities.registerObserver(mObserver); - mPersistentPreferredActivities.registerObserver(mObserver); - mCrossProfileIntentResolvers.registerObserver(mObserver); - mSharedUsers.registerObserver(mObserver); - mAppIds.registerObserver(mObserver); - mOtherAppIds.registerObserver(mObserver); - mRenamedPackages.registerObserver(mObserver); - mNextAppLinkGeneration.registerObserver(mObserver); - mDefaultBrowserApp.registerObserver(mObserver); - + registerObservers(); Watchable.verifyWatchedAttributes(this, mObserver); mSnapshot = makeCache(); @@ -629,7 +629,6 @@ public final class Settings implements Watchable, Snappable { * are changed by PackageManagerService APIs are deep-copied */ private Settings(Settings r) { - final int mPackagesSize = r.mPackages.size(); mPackages.putAll(r.mPackages); // The following assignments satisfy Java requirements but are not @@ -662,20 +661,23 @@ public final class Settings implements Watchable, Snappable { mSharedUsers.putAll(r.mSharedUsers); mAppIds = r.mAppIds.snapshot(); mOtherAppIds = r.mOtherAppIds.snapshot(); - mPastSignatures.addAll(r.mPastSignatures); - mKeySetRefs.putAll(r.mKeySetRefs); + WatchedArrayList.snapshot( + mPastSignatures, r.mPastSignatures); + WatchedArrayMap.snapshot( + mKeySetRefs, r.mKeySetRefs); mRenamedPackages.snapshot(r.mRenamedPackages); mNextAppLinkGeneration.snapshot(r.mNextAppLinkGeneration); mDefaultBrowserApp.snapshot(r.mDefaultBrowserApp); // mReadMessages - mPendingPackages.addAll(r.mPendingPackages); + WatchedArrayList.snapshot( + mPendingPackages, r.mPendingPackages); mSystemDir = null; // mKeySetManagerService; mPermissions = r.mPermissions; mPermissionDataProvider = r.mPermissionDataProvider; // Do not register any Watchables and do not create a snapshot cache. - mSnapshot = null; + mSnapshot = new SnapshotCache.Sealed(); } /** @@ -2326,7 +2328,7 @@ public final class Settings implements Watchable, Snappable { serializer.startTag(null, "shared-user"); serializer.attribute(null, ATTR_NAME, usr.name); serializer.attributeInt(null, "userId", usr.userId); - usr.signatures.writeXml(serializer, "sigs", mPastSignatures); + usr.signatures.writeXml(serializer, "sigs", mPastSignatures.untrackedStorage()); serializer.endTag(null, "shared-user"); } @@ -2736,11 +2738,11 @@ public final class Settings implements Watchable, Snappable { writeUsesStaticLibLPw(serializer, pkg.usesStaticLibraries, pkg.usesStaticLibrariesVersions); - pkg.signatures.writeXml(serializer, "sigs", mPastSignatures); + pkg.signatures.writeXml(serializer, "sigs", mPastSignatures.untrackedStorage()); if (installSource.initiatingPackageSignatures != null) { installSource.initiatingPackageSignatures.writeXml( - serializer, "install-initiator-sigs", mPastSignatures); + serializer, "install-initiator-sigs", mPastSignatures.untrackedStorage()); } writeSigningKeySetLPr(serializer, pkg.keySetData); @@ -2909,7 +2911,7 @@ public final class Settings implements Watchable, Snappable { } else if (TAG_READ_EXTERNAL_STORAGE.equals(tagName)) { // No longer used. } else if (tagName.equals("keyset-settings")) { - mKeySetManagerService.readKeySetsLPw(parser, mKeySetRefs); + mKeySetManagerService.readKeySetsLPw(parser, mKeySetRefs.untrackedStorage()); } else if (TAG_VERSION.equals(tagName)) { final String volumeUuid = XmlUtils.readStringAttribute(parser, ATTR_VOLUME_UUID); @@ -3697,7 +3699,7 @@ public final class Settings implements Watchable, Snappable { } else if (tagName.equals(TAG_ENABLED_COMPONENTS)) { readEnabledComponentsLPw(packageSetting, parser, 0); } else if (tagName.equals("sigs")) { - packageSetting.signatures.readXml(parser, mPastSignatures); + packageSetting.signatures.readXml(parser, mPastSignatures.untrackedStorage()); } else if (tagName.equals(TAG_PERMISSIONS)) { readInstallPermissionsLPr(parser, packageSetting.getLegacyPermissionState(), users); @@ -3728,7 +3730,7 @@ public final class Settings implements Watchable, Snappable { packageSetting.keySetData.addDefinedKeySet(id, alias); } else if (tagName.equals("install-initiator-sigs")) { final PackageSignatures signatures = new PackageSignatures(); - signatures.readXml(parser, mPastSignatures); + signatures.readXml(parser, mPastSignatures.untrackedStorage()); packageSetting.installSource = packageSetting.installSource.setInitiatingPackageSignatures(signatures); } else if (tagName.equals(TAG_DOMAIN_VERIFICATION)) { @@ -3923,7 +3925,7 @@ public final class Settings implements Watchable, Snappable { String tagName = parser.getName(); if (tagName.equals("sigs")) { - su.signatures.readXml(parser, mPastSignatures); + su.signatures.readXml(parser, mPastSignatures.untrackedStorage()); } else if (tagName.equals("perms")) { readInstallPermissionsLPr(parser, su.getLegacyPermissionState(), users); } else { diff --git a/services/core/java/com/android/server/pm/SnapshotStatistics.java b/services/core/java/com/android/server/pm/SnapshotStatistics.java index c425bad50ae87..7bf00603f1321 100644 --- a/services/core/java/com/android/server/pm/SnapshotStatistics.java +++ b/services/core/java/com/android/server/pm/SnapshotStatistics.java @@ -23,6 +23,7 @@ import android.os.Message; import android.os.SystemClock; import android.text.TextUtils; +import com.android.internal.annotations.GuardedBy; import com.android.server.EventLogTags; import java.io.PrintWriter; @@ -238,6 +239,11 @@ public class SnapshotStatistics { */ public int mTotalUsed = 0; + /** + * The total number of times a snapshot was bypassed because corking was in effect. + */ + public int mTotalCorked = 0; + /** * The total number of builds that count as big, which means they took longer than * SNAPSHOT_BIG_BUILD_TIME_NS. @@ -291,6 +297,13 @@ public class SnapshotStatistics { } } + /** + * Record a cork. + */ + private void corked() { + mTotalCorked++; + } + private Stats(long now) { mStartTimeUs = now; mTimes = new int[mTimeBins.count()]; @@ -308,6 +321,7 @@ public class SnapshotStatistics { mUsed = Arrays.copyOf(orig.mUsed, orig.mUsed.length); mTotalBuilds = orig.mTotalBuilds; mTotalUsed = orig.mTotalUsed; + mTotalCorked = orig.mTotalCorked; mBigBuilds = orig.mBigBuilds; mShortLived = orig.mShortLived; mTotalTimeUs = orig.mTotalTimeUs; @@ -365,6 +379,7 @@ public class SnapshotStatistics { * Dump the summary statistics record. Choose the header or the data. * number of builds * number of uses + * number of corks * number of big builds * number of short lifetimes * cumulative build time, in seconds @@ -373,13 +388,13 @@ public class SnapshotStatistics { private void dumpStats(PrintWriter pw, String indent, long now, boolean header) { dumpPrefix(pw, indent, now, header, "Summary stats"); if (header) { - pw.format(Locale.US, " %10s %10s %10s %10s %10s %10s", - "TotBlds", "TotUsed", "BigBlds", "ShortLvd", + pw.format(Locale.US, " %10s %10s %10s %10s %10s %10s %10s", + "TotBlds", "TotUsed", "TotCork", "BigBlds", "ShortLvd", "TotTime", "MaxTime"); } else { pw.format(Locale.US, - " %10d %10d %10d %10d %10d %10d", - mTotalBuilds, mTotalUsed, mBigBuilds, mShortLived, + " %10d %10d %10d %10d %10d %10d %10d", + mTotalBuilds, mTotalUsed, mTotalCorked, mBigBuilds, mShortLived, mTotalTimeUs / 1000, mMaxBuildTimeUs / 1000); } pw.println(); @@ -516,7 +531,7 @@ public class SnapshotStatistics { * @param done The time at which the snapshot rebuild completed, in ns. * @param hits The number of times the previous snapshot was used. */ - public void rebuild(long now, long done, int hits) { + public final void rebuild(long now, long done, int hits) { // The duration has a span of about 2000s final int duration = (int) (done - now); boolean reportEvent = false; @@ -543,10 +558,21 @@ public class SnapshotStatistics { } } + /** + * Record a corked snapshot request. + */ + public final void corked() { + synchronized (mLock) { + mShort[0].corked(); + mLong[0].corked(); + } + } + /** * Roll a stats array. Shift the elements up an index and create a new element at * index zero. The old element zero is completed with the specified time. */ + @GuardedBy("mLock") private void shift(Stats[] s, long now) { s[0].complete(now); for (int i = s.length - 1; i > 0; i--) { @@ -598,7 +624,8 @@ public class SnapshotStatistics { * Dump the statistics. The format is compatible with the PackageManager dumpsys * output. */ - public void dump(PrintWriter pw, String indent, long now, int unrecorded, boolean full) { + public void dump(PrintWriter pw, String indent, long now, int unrecorded, + int corkLevel, boolean full) { // Grab the raw statistics under lock, but print them outside of the lock. Stats[] l; Stats[] s; @@ -608,7 +635,8 @@ public class SnapshotStatistics { s = Arrays.copyOf(mShort, mShort.length); s[0] = new Stats(s[0]); } - pw.format(Locale.US, "%s Unrecorded hits %d", indent, unrecorded); + pw.format(Locale.US, "%s Unrecorded-hits: %d Cork-level: %d", indent, + unrecorded, corkLevel); pw.println(); dump(pw, indent, now, l, s, "stats"); if (!full) { diff --git a/services/core/java/com/android/server/utils/SnapshotCache.java b/services/core/java/com/android/server/utils/SnapshotCache.java index b4b8835ac0269..68eb4b09b3ab5 100644 --- a/services/core/java/com/android/server/utils/SnapshotCache.java +++ b/services/core/java/com/android/server/utils/SnapshotCache.java @@ -40,10 +40,10 @@ public abstract class SnapshotCache extends Watcher{ protected final T mSource; // The cached snapshot - private T mSnapshot = null; + private volatile T mSnapshot = null; // True if the snapshot is sealed and may not be modified. - private boolean mSealed = false; + private volatile boolean mSealed = false; /** * Create a cache with a source object for rebuilding snapshots and a @@ -69,7 +69,7 @@ public abstract class SnapshotCache extends Watcher{ * Notify the object that the source object has changed. If the local object is sealed then * IllegalStateException is thrown. Otherwise, the cache is cleared. */ - public void onChange(@Nullable Watchable what) { + public final void onChange(@Nullable Watchable what) { if (mSealed) { throw new IllegalStateException("attempt to change a sealed object"); } @@ -79,7 +79,7 @@ public abstract class SnapshotCache extends Watcher{ /** * Seal the cache. Attempts to modify the cache will generate an exception. */ - public void seal() { + public final void seal() { mSealed = true; } @@ -88,7 +88,7 @@ public abstract class SnapshotCache extends Watcher{ * new snapshot and saves it in the cache. * @return A snapshot as returned by createSnapshot() and possibly cached. */ - public T snapshot() { + public final T snapshot() { T s = mSnapshot; if (s == null || !ENABLED) { s = createSnapshot(); diff --git a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java index 709b009c2feb8..1b6bddc158b8b 100644 --- a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java @@ -25,6 +25,7 @@ import android.util.ArraySet; import android.util.LongSparseArray; import com.android.internal.util.ArrayUtils; +import com.android.server.utils.WatchedArrayMap; import java.io.File; import java.io.IOException; @@ -33,7 +34,7 @@ import java.security.cert.CertificateException; public class KeySetManagerServiceTest extends AndroidTestCase { - private ArrayMap mPackagesMap; + private WatchedArrayMap mPackagesMap; private KeySetManagerService mKsms; public PackageSetting generateFakePackageSetting(String name) { @@ -46,7 +47,7 @@ public class KeySetManagerServiceTest extends AndroidTestCase { @Override public void setUp() throws Exception { super.setUp(); - mPackagesMap = new ArrayMap(); + mPackagesMap = new WatchedArrayMap(); mKsms = new KeySetManagerService(mPackagesMap); } @@ -94,7 +95,8 @@ public class KeySetManagerServiceTest extends AndroidTestCase { } public void testEncodePublicKey() throws IOException { - ArrayMap packagesMap = new ArrayMap(); + WatchedArrayMap packagesMap = + new WatchedArrayMap(); KeySetManagerService ksms = new KeySetManagerService(packagesMap); PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA); diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java index a2311690744e3..29f4aa976ef61 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java @@ -47,7 +47,6 @@ import android.os.BaseBundle; import android.os.PersistableBundle; import android.os.Process; import android.os.UserHandle; -import android.util.ArrayMap; import android.util.ArraySet; import android.util.AtomicFile; import android.util.Log; @@ -64,6 +63,7 @@ import com.android.server.pm.parsing.pkg.ParsedPackage; import com.android.server.pm.permission.LegacyPermissionDataProvider; import com.android.server.pm.verify.domain.DomainVerificationManagerInternal; import com.android.server.utils.WatchableTester; +import com.android.server.utils.WatchedArrayMap; import com.google.common.truth.Truth; @@ -1202,9 +1202,8 @@ public class PackageManagerSettingsTests { private void verifyKeySetMetaData(Settings settings) throws ReflectiveOperationException, IllegalAccessException { - ArrayMap packages = - settings.mPackages.untrackedStorage(); - KeySetManagerService ksms = settings.mKeySetManagerService; + WatchedArrayMap packages = settings.mPackages; + KeySetManagerService ksms = settings.getKeySetManagerService(); /* verify keyset and public key ref counts */ assertThat(KeySetUtils.getKeySetRefCount(ksms, 1), is(2));