Merge changes I8dc57930,Ia993613f,I111cc425 into sc-dev

* changes:
  Enable PackageManagerService snapshots
  Improve snapshot performance
  Correct snapshot races
This commit is contained in:
TreeHugger Robot
2021-05-12 18:42:25 +00:00
committed by Android (Google) Code Review
8 changed files with 324 additions and 115 deletions

View File

@@ -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;
}
}

View File

@@ -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<ArraySet<Long>> mKeySetMapping;
private final ArrayMap<String, PackageSetting> mPackages;
private final WatchedArrayMap<String, PackageSetting> mPackages;
private long lastIssuedKeySetId = 0;
@@ -114,7 +115,7 @@ public class KeySetManagerService {
}
}
public KeySetManagerService(ArrayMap<String, PackageSetting> packages) {
public KeySetManagerService(WatchedArrayMap<String, PackageSetting> packages) {
mKeySets = new LongSparseArray<KeySetHandle>();
mPublicKeys = new LongSparseArray<PublicKeyHandle>();
mKeySetMapping = new LongSparseArray<ArraySet<Long>>();

View File

@@ -404,6 +404,7 @@ import com.android.server.pm.verify.domain.proxy.DomainVerificationProxyV2;
import com.android.server.rollback.RollbackManagerInternal;
import com.android.server.storage.DeviceStorageMonitorInternal;
import com.android.server.uri.UriGrantsManagerInternal;
import com.android.server.utils.SnapshotCache;
import com.android.server.utils.TimingsTraceAndSlog;
import com.android.server.utils.Watchable;
import com.android.server.utils.Watched;
@@ -871,12 +872,17 @@ public class PackageManagerService extends IPackageManager.Stub
@Watched
@GuardedBy("mLock")
final WatchedArrayMap<String, AndroidPackage> mPackages = new WatchedArrayMap<>();
private final SnapshotCache<WatchedArrayMap<String, AndroidPackage>> mPackagesSnapshot =
new SnapshotCache.Auto(mPackages, mPackages, "PackageManagerService.mPackages");
// Keys are isolated uids and values are the uid of the application
// that created the isolated process.
@Watched
@GuardedBy("mLock")
final WatchedSparseIntArray mIsolatedOwners = new WatchedSparseIntArray();
private final SnapshotCache<WatchedSparseIntArray> mIsolatedOwnersSnapshot =
new SnapshotCache.Auto(mIsolatedOwners, mIsolatedOwners,
"PackageManagerService.mIsolatedOwners");
/**
* Tracks new system packages [received in an OTA] that we expect to
@@ -1309,14 +1315,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();
}
}
@@ -1395,14 +1404,27 @@ public class PackageManagerService extends IPackageManager.Stub
@Watched
final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>
mSharedLibraries = new WatchedArrayMap<>();
private final SnapshotCache<WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>>
mSharedLibrariesSnapshot =
new SnapshotCache.Auto<>(mSharedLibraries, mSharedLibraries,
"PackageManagerService.mSharedLibraries");
@Watched
final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>
mStaticLibsByDeclaringPackage = new WatchedArrayMap<>();
private final SnapshotCache<WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>>
mStaticLibsByDeclaringPackageSnapshot =
new SnapshotCache.Auto<>(mSharedLibraries, mSharedLibraries,
"PackageManagerService.mSharedLibraries");
// Mapping from instrumentation class names to info about them.
@Watched
final WatchedArrayMap<ComponentName, ParsedInstrumentation> mInstrumentation =
new WatchedArrayMap<>();
private final SnapshotCache<WatchedArrayMap<ComponentName, ParsedInstrumentation>>
mInstrumentationSnapshot =
new SnapshotCache.Auto<>(mInstrumentation, mInstrumentation,
"PackageManagerService.mInstrumentation");
// Packages whose data we have transfered into another package, thus
// should no longer exist.
@@ -1588,6 +1610,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;
@@ -1834,11 +1857,11 @@ public class PackageManagerService extends IPackageManager.Stub
Snapshot(int type) {
if (type == Snapshot.SNAPPED) {
settings = mSettings.snapshot();
isolatedOwners = mIsolatedOwners.snapshot();
packages = mPackages.snapshot();
sharedLibs = mSharedLibraries.snapshot();
staticLibs = mStaticLibsByDeclaringPackage.snapshot();
instrumentation = mInstrumentation.snapshot();
isolatedOwners = mIsolatedOwnersSnapshot.snapshot();
packages = mPackagesSnapshot.snapshot();
sharedLibs = mSharedLibrariesSnapshot.snapshot();
staticLibs = mStaticLibsByDeclaringPackageSnapshot.snapshot();
instrumentation = mInstrumentationSnapshot.snapshot();
resolveComponentName = mResolveComponentName.clone();
resolveActivity = new ActivityInfo(mResolveActivity);
instantAppInstallerActivity =
@@ -4874,12 +4897,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
@@ -4897,7 +4924,10 @@ public class PackageManagerService extends IPackageManager.Stub
// The snapshot disable/enable switch. An image with the flag set true uses snapshots
// and an image with the flag set false does not use snapshots.
private static final boolean SNAPSHOT_ENABLED = false;
private static final boolean SNAPSHOT_ENABLED = true;
// 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.
@@ -4922,15 +4952,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 +4969,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 +4987,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 +4999,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 +5038,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 +5419,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 +6442,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 +18581,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
@GuardedBy({"mInstallLock", "mLock"})
@GuardedBy("mInstallLock")
private void installPackagesTracedLI(List<InstallRequest> requests) {
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages");
@@ -24018,6 +24078,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 +24422,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());
}
}
}

View File

@@ -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;
@@ -364,19 +365,21 @@ public final class Settings implements Watchable, Snappable {
/** Map from package name to settings */
@Watched
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
final WatchedArrayMap<String, PackageSetting> mPackages = new WatchedArrayMap<>();
final WatchedArrayMap<String, PackageSetting> mPackages;
private final SnapshotCache<WatchedArrayMap<String, PackageSetting>> mPackagesSnapshot;
/**
* List of packages that were involved in installing other packages, i.e. are listed
* in at least one app's InstallSource.
*/
@Watched
private final WatchedArraySet<String> mInstallerPackages = new WatchedArraySet<>();
private final WatchedArraySet<String> mInstallerPackages;
private final SnapshotCache<WatchedArraySet<String>> mInstallerPackagesSnapshot;
/** Map from package name to appId and excluded userids */
@Watched
private final WatchedArrayMap<String, KernelPackageState> mKernelMapping =
new WatchedArrayMap<>();
private final WatchedArrayMap<String, KernelPackageState> mKernelMapping;
private final SnapshotCache<WatchedArrayMap<String, KernelPackageState>> mKernelMappingSnapshot;
// List of replaced system applications
@Watched
@@ -397,7 +400,7 @@ public final class Settings implements Watchable, Snappable {
/** Map from volume UUID to {@link VersionInfo} */
@Watched
private WatchedArrayMap<String, VersionInfo> mVersion = new WatchedArrayMap<>();
private final WatchedArrayMap<String, VersionInfo> mVersion = new WatchedArrayMap<>();
/**
* Version details for a storage volume that may hold apps.
@@ -435,6 +438,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 +466,12 @@ public final class Settings implements Watchable, Snappable {
private final WatchedSparseArray<SettingBase> mOtherAppIds;
// For reading/writing settings file.
private final ArrayList<Signature> mPastSignatures =
new ArrayList<Signature>();
private final ArrayMap<Long, Integer> mKeySetRefs =
new ArrayMap<Long, Integer>();
@Watched
private final WatchedArrayList<Signature> mPastSignatures =
new WatchedArrayList<Signature>();
@Watched
private final WatchedArrayMap<Long, Integer> mKeySetRefs =
new WatchedArrayMap<Long, Integer>();
// Packages that have been renamed since they were first installed.
// Keys are the new names of the packages, values are the original
@@ -495,18 +501,21 @@ 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<PackageSetting> mPendingPackages = new ArrayList<>();
@Watched
private final WatchedArrayList<PackageSetting> mPendingPackages = new WatchedArrayList<>();
private final File mSystemDir;
public final KeySetManagerService mKeySetManagerService =
new KeySetManagerService(mPackages.untrackedStorage());
private final KeySetManagerService mKeySetManagerService;
/** 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,23 +541,7 @@ public final class Settings implements Watchable, Snappable {
}};
}
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
public Settings(Map<String, PackageSetting> pkgSettings) {
mLock = new PackageManagerTracedLock();
mPackages.putAll(pkgSettings);
mAppIds = new WatchedArrayList<>();
mOtherAppIds = new WatchedSparseArray<>();
mSystemDir = null;
mPermissions = null;
mRuntimePermissionsPersistence = null;
mPermissionDataProvider = null;
mSettingsFilename = null;
mBackupSettingsFilename = null;
mPackageListFilename = null;
mStoppedPackagesFilename = null;
mBackupStoppedPackagesFilename = null;
mKernelMappingFilename = null;
mDomainVerificationManager = null;
private void registerObservers() {
mPackages.registerObserver(mObserver);
mInstallerPackages.registerObserver(mObserver);
mKernelMapping.registerObserver(mObserver);
@@ -564,7 +557,43 @@ public final class Settings implements Watchable, Snappable {
mRenamedPackages.registerObserver(mObserver);
mNextAppLinkGeneration.registerObserver(mObserver);
mDefaultBrowserApp.registerObserver(mObserver);
mPendingPackages.registerObserver(mObserver);
mPastSignatures.registerObserver(mObserver);
mKeySetRefs.registerObserver(mObserver);
}
// CONSTRUCTOR
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
public Settings(Map<String, PackageSetting> pkgSettings) {
mPackages = new WatchedArrayMap<>();
mPackagesSnapshot =
new SnapshotCache.Auto<>(mPackages, mPackages, "Settings.mPackages");
mKernelMapping = new WatchedArrayMap<>();
mKernelMappingSnapshot =
new SnapshotCache.Auto<>(mKernelMapping, mKernelMapping, "Settings.mKernelMapping");
mInstallerPackages = new WatchedArraySet<>();
mInstallerPackagesSnapshot =
new SnapshotCache.Auto<>(mInstallerPackages, mInstallerPackages,
"Settings.mInstallerPackages");
mKeySetManagerService = new KeySetManagerService(mPackages);
mLock = new PackageManagerTracedLock();
mPackages.putAll(pkgSettings);
mAppIds = new WatchedArrayList<>();
mOtherAppIds = new WatchedSparseArray<>();
mSystemDir = null;
mPermissions = null;
mRuntimePermissionsPersistence = null;
mPermissionDataProvider = null;
mSettingsFilename = null;
mBackupSettingsFilename = null;
mPackageListFilename = null;
mStoppedPackagesFilename = null;
mBackupStoppedPackagesFilename = null;
mKernelMappingFilename = null;
mDomainVerificationManager = null;
registerObservers();
Watchable.verifyWatchedAttributes(this, mObserver);
mSnapshot = makeCache();
@@ -574,6 +603,18 @@ public final class Settings implements Watchable, Snappable {
LegacyPermissionDataProvider permissionDataProvider,
@NonNull DomainVerificationManagerInternal domainVerificationManager,
@NonNull PackageManagerTracedLock lock) {
mPackages = new WatchedArrayMap<>();
mPackagesSnapshot =
new SnapshotCache.Auto<>(mPackages, mPackages, "Settings.mPackages");
mKernelMapping = new WatchedArrayMap<>();
mKernelMappingSnapshot =
new SnapshotCache.Auto<>(mKernelMapping, mKernelMapping, "Settings.mKernelMapping");
mInstallerPackages = new WatchedArraySet<>();
mInstallerPackagesSnapshot =
new SnapshotCache.Auto<>(mInstallerPackages, mInstallerPackages,
"Settings.mInstallerPackages");
mKeySetManagerService = new KeySetManagerService(mPackages);
mLock = lock;
mAppIds = new WatchedArrayList<>();
mOtherAppIds = new WatchedSparseArray<>();
@@ -602,22 +643,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,8 +655,13 @@ 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);
mPackages = r.mPackagesSnapshot.snapshot();
mPackagesSnapshot = new SnapshotCache.Sealed<>();
mKernelMapping = r.mKernelMappingSnapshot.snapshot();
mKernelMappingSnapshot = new SnapshotCache.Sealed<>();
mInstallerPackages = r.mInstallerPackagesSnapshot.snapshot();
mInstallerPackagesSnapshot = new SnapshotCache.Sealed<>();
mKeySetManagerService = new KeySetManagerService(mPackages);
// The following assignments satisfy Java requirements but are not
// needed by the read-only methods. Note especially that the lock
@@ -647,9 +678,7 @@ public final class Settings implements Watchable, Snappable {
mDomainVerificationManager = r.mDomainVerificationManager;
mInstallerPackages.addAll(r.mInstallerPackages);
mKernelMapping.putAll(r.mKernelMapping);
mDisabledSysPackages.putAll(r.mDisabledSysPackages);
mDisabledSysPackages.snapshot(r.mDisabledSysPackages);
mBlockUninstallPackages.snapshot(r.mBlockUninstallPackages);
mVersion.putAll(r.mVersion);
mVerifierDeviceIdentity = r.mVerifierDeviceIdentity;
@@ -659,23 +688,26 @@ public final class Settings implements Watchable, Snappable {
mPersistentPreferredActivities, r.mPersistentPreferredActivities);
WatchedSparseArray.snapshot(
mCrossProfileIntentResolvers, r.mCrossProfileIntentResolvers);
mSharedUsers.putAll(r.mSharedUsers);
mSharedUsers.snapshot(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 +2358,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 +2768,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 +2941,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 +3729,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 +3760,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 +3955,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 {

View File

@@ -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) {

View File

@@ -19,6 +19,9 @@ package com.android.server.utils;
import android.annotation.NonNull;
import android.annotation.Nullable;
import java.util.WeakHashMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
* A class that caches snapshots. Instances are instantiated on a {@link Watchable}; when the
* {@link Watchable} reports a change, the cache is cleared. The snapshot() method fetches the
@@ -35,25 +38,65 @@ public abstract class SnapshotCache<T> extends Watcher{
*/
private static final boolean ENABLED = true;
/**
* The statistics for a single cache. The object records the number of times a
* snapshot was reused and the number of times a snapshot was rebuilt.
*/
private static class Statistics {
final String mName;
private final AtomicInteger mReused = new AtomicInteger(0);
private final AtomicInteger mRebuilt = new AtomicInteger(0);
Statistics(@NonNull String n) {
mName = n;
}
}
// The source object from which snapshots are created. This may be null if createSnapshot()
// does not require it.
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;
// The statistics for this cache. This may be null.
private final Statistics mStatistics;
/**
* The global list of caches.
*/
private static final WeakHashMap<SnapshotCache, Void> sCaches = new WeakHashMap<>();
/**
* Create a cache with a source object for rebuilding snapshots and a
* {@link Watchable} that notifies when the cache is invalid.
* {@link Watchable} that notifies when the cache is invalid. If the name is null
* then statistics are not collected for this cache.
* @param source Source data for rebuilding snapshots.
* @param watchable The object that notifies when the cache is invalid.
* @param name The name of the cache, for statistics reporting.
*/
public SnapshotCache(@Nullable T source, @NonNull Watchable watchable, @Nullable String name) {
mSource = source;
watchable.registerObserver(this);
if (name != null) {
mStatistics = new Statistics(name);
sCaches.put(this, null);
} else {
mStatistics = null;
}
}
/**
* Create a cache with a source object for rebuilding snapshots and a
* {@link Watchable} that notifies when the cache is invalid. The name is null in
* this API.
* @param source Source data for rebuilding snapshots.
* @param watchable The object that notifies when the cache is invalid.
*/
public SnapshotCache(@Nullable T source, @NonNull Watchable watchable) {
mSource = source;
watchable.registerObserver(this);
this(source, watchable, null);
}
/**
@@ -63,13 +106,14 @@ public abstract class SnapshotCache<T> extends Watcher{
public SnapshotCache() {
mSource = null;
mSealed = true;
mStatistics = null;
}
/**
* 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 +123,7 @@ public abstract class SnapshotCache<T> extends Watcher{
/**
* Seal the cache. Attempts to modify the cache will generate an exception.
*/
public void seal() {
public final void seal() {
mSealed = true;
}
@@ -88,11 +132,14 @@ public abstract class SnapshotCache<T> 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();
mSnapshot = s;
if (mStatistics != null) mStatistics.mRebuilt.incrementAndGet();
} else {
if (mStatistics != null) mStatistics.mReused.incrementAndGet();
}
return s;
}
@@ -123,4 +170,25 @@ public abstract class SnapshotCache<T> extends Watcher{
throw new UnsupportedOperationException("cannot snapshot a sealed snaphot");
}
}
/**
* A snapshot cache suitable for Snappable types. The key is that Snappable types
* have a known implementation of createSnapshot() so that this class is concrete.
* @param <T> The class whose snapshot is being cached.
*/
public static class Auto<T extends Snappable<T>> extends SnapshotCache<T> {
public Auto(@NonNull T source, @NonNull Watchable watchable, @Nullable String name) {
super(source, watchable, name);
}
public Auto(@NonNull T source, @NonNull Watchable watchable) {
this(source, watchable, null);
}
/**
* Concrete createSnapshot() using the snapshot() method of <T>.
*/
public T createSnapshot() {
return mSource.snapshot();
}
}
}

View File

@@ -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<String, PackageSetting> mPackagesMap;
private WatchedArrayMap<String, PackageSetting> 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<String, PackageSetting>();
mPackagesMap = new WatchedArrayMap<String, PackageSetting>();
mKsms = new KeySetManagerService(mPackagesMap);
}
@@ -94,7 +95,8 @@ public class KeySetManagerServiceTest extends AndroidTestCase {
}
public void testEncodePublicKey() throws IOException {
ArrayMap<String, PackageSetting> packagesMap = new ArrayMap<String, PackageSetting>();
WatchedArrayMap<String, PackageSetting> packagesMap =
new WatchedArrayMap<String, PackageSetting>();
KeySetManagerService ksms = new KeySetManagerService(packagesMap);
PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);

View File

@@ -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<String, PackageSetting> packages =
settings.mPackages.untrackedStorage();
KeySetManagerService ksms = settings.mKeySetManagerService;
WatchedArrayMap<String, PackageSetting> packages = settings.mPackages;
KeySetManagerService ksms = settings.getKeySetManagerService();
/* verify keyset and public key ref counts */
assertThat(KeySetUtils.getKeySetRefCount(ksms, 1), is(2));