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 mTitlePrinted;
private boolean mFullPreferred; private boolean mFullPreferred;
private boolean mCheckIn; private boolean mCheckIn;
private boolean mBrief;
private String mTargetPackageName; private String mTargetPackageName;
@@ -128,4 +129,12 @@ public final class DumpState {
public void setCheckIn(boolean checkIn) { public void setCheckIn(boolean checkIn) {
mCheckIn = 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 android.util.TypedXmlSerializer;
import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.utils.WatchedArrayMap;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserException;
@@ -65,7 +66,7 @@ public class KeySetManagerService {
protected final LongSparseArray<ArraySet<Long>> mKeySetMapping; protected final LongSparseArray<ArraySet<Long>> mKeySetMapping;
private final ArrayMap<String, PackageSetting> mPackages; private final WatchedArrayMap<String, PackageSetting> mPackages;
private long lastIssuedKeySetId = 0; 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>(); mKeySets = new LongSparseArray<KeySetHandle>();
mPublicKeys = new LongSparseArray<PublicKeyHandle>(); mPublicKeys = new LongSparseArray<PublicKeyHandle>();
mKeySetMapping = new LongSparseArray<ArraySet<Long>>(); 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.rollback.RollbackManagerInternal;
import com.android.server.storage.DeviceStorageMonitorInternal; import com.android.server.storage.DeviceStorageMonitorInternal;
import com.android.server.uri.UriGrantsManagerInternal; import com.android.server.uri.UriGrantsManagerInternal;
import com.android.server.utils.SnapshotCache;
import com.android.server.utils.TimingsTraceAndSlog; import com.android.server.utils.TimingsTraceAndSlog;
import com.android.server.utils.Watchable; import com.android.server.utils.Watchable;
import com.android.server.utils.Watched; import com.android.server.utils.Watched;
@@ -871,12 +872,17 @@ public class PackageManagerService extends IPackageManager.Stub
@Watched @Watched
@GuardedBy("mLock") @GuardedBy("mLock")
final WatchedArrayMap<String, AndroidPackage> mPackages = new WatchedArrayMap<>(); 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 // Keys are isolated uids and values are the uid of the application
// that created the isolated process. // that created the isolated process.
@Watched @Watched
@GuardedBy("mLock") @GuardedBy("mLock")
final WatchedSparseIntArray mIsolatedOwners = new WatchedSparseIntArray(); 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 * 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 // 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 // writes if the cache isn't enabled yet. We re-enable writes later when we're
// done initializing. // done initializing.
sSnapshotCorked = true; sSnapshotCorked.incrementAndGet();
PackageManager.corkPackageInfoCache(); PackageManager.corkPackageInfoCache();
} }
@Override @Override
public void enablePackageCaches() { public void enablePackageCaches() {
// Uncork cache invalidations and allow clients to cache package information. // 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(); PackageManager.uncorkPackageInfoCache();
} }
} }
@@ -1395,14 +1404,27 @@ public class PackageManagerService extends IPackageManager.Stub
@Watched @Watched
final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>> final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>
mSharedLibraries = new WatchedArrayMap<>(); mSharedLibraries = new WatchedArrayMap<>();
private final SnapshotCache<WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>>
mSharedLibrariesSnapshot =
new SnapshotCache.Auto<>(mSharedLibraries, mSharedLibraries,
"PackageManagerService.mSharedLibraries");
@Watched @Watched
final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>> final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>
mStaticLibsByDeclaringPackage = new WatchedArrayMap<>(); 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. // Mapping from instrumentation class names to info about them.
@Watched @Watched
final WatchedArrayMap<ComponentName, ParsedInstrumentation> mInstrumentation = final WatchedArrayMap<ComponentName, ParsedInstrumentation> mInstrumentation =
new WatchedArrayMap<>(); 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 // Packages whose data we have transfered into another package, thus
// should no longer exist. // should no longer exist.
@@ -1588,6 +1610,7 @@ public class PackageManagerService extends IPackageManager.Stub
static final int INTEGRITY_VERIFICATION_COMPLETE = 25; static final int INTEGRITY_VERIFICATION_COMPLETE = 25;
static final int CHECK_PENDING_INTEGRITY_VERIFICATION = 26; static final int CHECK_PENDING_INTEGRITY_VERIFICATION = 26;
static final int DOMAIN_VERIFICATION = 27; 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_POST_DELETE_DELAY_MS = 3 * 1000;
static final int DEFERRED_NO_KILL_INSTALL_OBSERVER_DELAY_MS = 500; static final int DEFERRED_NO_KILL_INSTALL_OBSERVER_DELAY_MS = 500;
@@ -1834,11 +1857,11 @@ public class PackageManagerService extends IPackageManager.Stub
Snapshot(int type) { Snapshot(int type) {
if (type == Snapshot.SNAPPED) { if (type == Snapshot.SNAPPED) {
settings = mSettings.snapshot(); settings = mSettings.snapshot();
isolatedOwners = mIsolatedOwners.snapshot(); isolatedOwners = mIsolatedOwnersSnapshot.snapshot();
packages = mPackages.snapshot(); packages = mPackagesSnapshot.snapshot();
sharedLibs = mSharedLibraries.snapshot(); sharedLibs = mSharedLibrariesSnapshot.snapshot();
staticLibs = mStaticLibsByDeclaringPackage.snapshot(); staticLibs = mStaticLibsByDeclaringPackageSnapshot.snapshot();
instrumentation = mInstrumentation.snapshot(); instrumentation = mInstrumentationSnapshot.snapshot();
resolveComponentName = mResolveComponentName.clone(); resolveComponentName = mResolveComponentName.clone();
resolveActivity = new ActivityInfo(mResolveActivity); resolveActivity = new ActivityInfo(mResolveActivity);
instantAppInstallerActivity = instantAppInstallerActivity =
@@ -4874,12 +4897,16 @@ public class PackageManagerService extends IPackageManager.Stub
// A lock-free cache for frequently called functions. // A lock-free cache for frequently called functions.
private volatile Computer mSnapshotComputer; private volatile Computer mSnapshotComputer;
// If true, the snapshot is invalid (stale). The attribute is static since it may be // If true, the snapshot is invalid (stale). The attribute is static since it may be
// set from outside classes. // set from outside classes. The attribute may be set to true anywhere, although it
private static volatile boolean sSnapshotInvalid = true; // 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 // 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 // computer. This throttles snapshot creation during periods of churn in Package
// Manager. // 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 * 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 // 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. // 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 // The per-instance snapshot disable/enable flag. This is generally set to false in
// test instances and set to SNAPSHOT_ENABLED in operational instances. // 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 // 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. // yet invalidated the snapshot. Always give the thread the live computer.
return mLiveComputer; 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) { synchronized (mSnapshotLock) {
// This synchronization block serializes access to the snapshot computer and
// to the code that samples mSnapshotInvalid.
Computer c = mSnapshotComputer; Computer c = mSnapshotComputer;
if (sSnapshotCorked && (c != null)) { if (sSnapshotInvalid.getAndSet(false) || (c == null)) {
// Snapshots are corked, which means new ones should not be built right now.
c.use();
return c;
}
if (sSnapshotInvalid || (c == null)) {
// The snapshot is invalid if it is marked as invalid or if it is null. If it // 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(). // is null, then it is currently being rebuilt by rebuildSnapshot().
synchronized (mLock) { synchronized (mLock) {
@@ -4938,9 +4969,7 @@ public class PackageManagerService extends IPackageManager.Stub
// invalidated as it is rebuilt. However, the snapshot is still // invalidated as it is rebuilt. However, the snapshot is still
// self-consistent (the lock is being held) and is current as of the time // self-consistent (the lock is being held) and is current as of the time
// this function is entered. // this function is entered.
if (sSnapshotInvalid) { rebuildSnapshot();
rebuildSnapshot();
}
// Guaranteed to be non-null. mSnapshotComputer is only be set to null // Guaranteed to be non-null. mSnapshotComputer is only be set to null
// temporarily in rebuildSnapshot(), which is guarded by mLock(). Since // 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 * Rebuild the cached computer. mSnapshotComputer is temporarily set to null to block other
* threads from using the invalid computer until it is rebuilt. * threads from using the invalid computer until it is rebuilt.
*/ */
@GuardedBy("mLock") @GuardedBy({ "mLock", "mSnapshotLock"})
private void rebuildSnapshot() { private void rebuildSnapshot() {
final long now = SystemClock.currentTimeMicro(); final long now = SystemClock.currentTimeMicro();
final int hits = mSnapshotComputer == null ? -1 : mSnapshotComputer.getUsed(); final int hits = mSnapshotComputer == null ? -1 : mSnapshotComputer.getUsed();
mSnapshotComputer = null; mSnapshotComputer = null;
sSnapshotInvalid = false;
final Snapshot args = new Snapshot(Snapshot.SNAPPED); final Snapshot args = new Snapshot(Snapshot.SNAPPED);
mSnapshotComputer = new ComputerEngine(args); mSnapshotComputer = new ComputerEngine(args);
final long done = SystemClock.currentTimeMicro(); final long done = SystemClock.currentTimeMicro();
@@ -4971,6 +4999,30 @@ public class PackageManagerService extends IPackageManager.Stub
mSnapshotStatistics.rebuild(now, done, hits); 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 * Create a live computer
*/ */
@@ -4986,9 +5038,9 @@ public class PackageManagerService extends IPackageManager.Stub
*/ */
public static void onChange(@Nullable Watchable what) { public static void onChange(@Nullable Watchable what) {
if (TRACE_SNAPSHOTS) { 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); mDomainVerificationManager.runMessage(messageCode, object);
break; 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 // 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 // corked initially to ensure a cached computer is not built until the end of the
// constructor. // constructor.
mSnapshotEnabled = SNAPSHOT_ENABLED;
sSnapshotCorked = true;
sSnapshotInvalid = true;
mSnapshotStatistics = new SnapshotStatistics(); mSnapshotStatistics = new SnapshotStatistics();
sSnapshotConsumer = this;
sSnapshotCorked.set(1);
sSnapshotInvalid.set(true);
mLiveComputer = createLiveComputer(); mLiveComputer = createLiveComputer();
mSnapshotComputer = null; mSnapshotComputer = null;
mSnapshotEnabled = SNAPSHOT_ENABLED;
registerObserver(); registerObserver();
} }
@@ -18521,7 +18581,7 @@ public class PackageManagerService extends IPackageManager.Stub
} }
} }
@GuardedBy({"mInstallLock", "mLock"}) @GuardedBy("mInstallLock")
private void installPackagesTracedLI(List<InstallRequest> requests) { private void installPackagesTracedLI(List<InstallRequest> requests) {
try { try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages"); 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); dumpState.setDump(DumpState.DUMP_PER_UID_READ_TIMEOUTS);
} else if ("snapshot".equals(cmd)) { } else if ("snapshot".equals(cmd)) {
dumpState.setDump(DumpState.DUMP_SNAPSHOT_STATISTICS); 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)) { } else if ("write".equals(cmd)) {
synchronized (mLock) { synchronized (mLock) {
writeSettingsLPrTEMP(); writeSettingsLPrTEMP();
@@ -24353,13 +24422,14 @@ public class PackageManagerService extends IPackageManager.Stub
pw.println(" Snapshots disabled"); pw.println(" Snapshots disabled");
} else { } else {
int hits = 0; int hits = 0;
int level = sSnapshotCorked.get();
synchronized (mSnapshotLock) { synchronized (mSnapshotLock) {
if (mSnapshotComputer != null) { if (mSnapshotComputer != null) {
hits = mSnapshotComputer.getUsed(); hits = mSnapshotComputer.getUsed();
} }
} }
final long now = SystemClock.currentTimeMicro(); 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; private final PackageManagerTracedLock mLock;
@Watched(manual = true)
private final RuntimePermissionPersistence mRuntimePermissionsPersistence; private final RuntimePermissionPersistence mRuntimePermissionsPersistence;
private final File mSettingsFilename; private final File mSettingsFilename;
@@ -364,19 +365,21 @@ public final class Settings implements Watchable, Snappable {
/** Map from package name to settings */ /** Map from package name to settings */
@Watched @Watched
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) @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 * List of packages that were involved in installing other packages, i.e. are listed
* in at least one app's InstallSource. * in at least one app's InstallSource.
*/ */
@Watched @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 */ /** Map from package name to appId and excluded userids */
@Watched @Watched
private final WatchedArrayMap<String, KernelPackageState> mKernelMapping = private final WatchedArrayMap<String, KernelPackageState> mKernelMapping;
new WatchedArrayMap<>(); private final SnapshotCache<WatchedArrayMap<String, KernelPackageState>> mKernelMappingSnapshot;
// List of replaced system applications // List of replaced system applications
@Watched @Watched
@@ -397,7 +400,7 @@ public final class Settings implements Watchable, Snappable {
/** Map from volume UUID to {@link VersionInfo} */ /** Map from volume UUID to {@link VersionInfo} */
@Watched @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. * 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. */ /** Device identity for the purpose of package verification. */
@Watched(manual = true)
private VerifierDeviceIdentity mVerifierDeviceIdentity; private VerifierDeviceIdentity mVerifierDeviceIdentity;
// The user's preferred activities associated with particular intent // 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; private final WatchedSparseArray<SettingBase> mOtherAppIds;
// For reading/writing settings file. // For reading/writing settings file.
private final ArrayList<Signature> mPastSignatures = @Watched
new ArrayList<Signature>(); private final WatchedArrayList<Signature> mPastSignatures =
private final ArrayMap<Long, Integer> mKeySetRefs = new WatchedArrayList<Signature>();
new ArrayMap<Long, Integer>(); @Watched
private final WatchedArrayMap<Long, Integer> mKeySetRefs =
new WatchedArrayMap<Long, Integer>();
// Packages that have been renamed since they were first installed. // Packages that have been renamed since they were first installed.
// Keys are the new names of the packages, values are the original // 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 * TODO: make this just a local variable that is passed in during package
* scanning to make it less confusing. * 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; private final File mSystemDir;
public final KeySetManagerService mKeySetManagerService = private final KeySetManagerService mKeySetManagerService;
new KeySetManagerService(mPackages.untrackedStorage());
/** Settings and other information about permissions */ /** Settings and other information about permissions */
@Watched(manual = true)
final LegacyPermissionSettings mPermissions; final LegacyPermissionSettings mPermissions;
@Watched(manual = true)
private final LegacyPermissionDataProvider mPermissionDataProvider; private final LegacyPermissionDataProvider mPermissionDataProvider;
@Watched(manual = true)
private final DomainVerificationManagerInternal mDomainVerificationManager; private final DomainVerificationManagerInternal mDomainVerificationManager;
/** /**
@@ -532,23 +541,7 @@ public final class Settings implements Watchable, Snappable {
}}; }};
} }
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) private void registerObservers() {
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;
mPackages.registerObserver(mObserver); mPackages.registerObserver(mObserver);
mInstallerPackages.registerObserver(mObserver); mInstallerPackages.registerObserver(mObserver);
mKernelMapping.registerObserver(mObserver); mKernelMapping.registerObserver(mObserver);
@@ -564,7 +557,43 @@ public final class Settings implements Watchable, Snappable {
mRenamedPackages.registerObserver(mObserver); mRenamedPackages.registerObserver(mObserver);
mNextAppLinkGeneration.registerObserver(mObserver); mNextAppLinkGeneration.registerObserver(mObserver);
mDefaultBrowserApp.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); Watchable.verifyWatchedAttributes(this, mObserver);
mSnapshot = makeCache(); mSnapshot = makeCache();
@@ -574,6 +603,18 @@ public final class Settings implements Watchable, Snappable {
LegacyPermissionDataProvider permissionDataProvider, LegacyPermissionDataProvider permissionDataProvider,
@NonNull DomainVerificationManagerInternal domainVerificationManager, @NonNull DomainVerificationManagerInternal domainVerificationManager,
@NonNull PackageManagerTracedLock lock) { @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; mLock = lock;
mAppIds = new WatchedArrayList<>(); mAppIds = new WatchedArrayList<>();
mOtherAppIds = new WatchedSparseArray<>(); mOtherAppIds = new WatchedSparseArray<>();
@@ -602,22 +643,7 @@ public final class Settings implements Watchable, Snappable {
mDomainVerificationManager = domainVerificationManager; mDomainVerificationManager = domainVerificationManager;
mPackages.registerObserver(mObserver); registerObservers();
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);
Watchable.verifyWatchedAttributes(this, mObserver); Watchable.verifyWatchedAttributes(this, mObserver);
mSnapshot = makeCache(); mSnapshot = makeCache();
@@ -629,8 +655,13 @@ public final class Settings implements Watchable, Snappable {
* are changed by PackageManagerService APIs are deep-copied * are changed by PackageManagerService APIs are deep-copied
*/ */
private Settings(Settings r) { private Settings(Settings r) {
final int mPackagesSize = r.mPackages.size(); mPackages = r.mPackagesSnapshot.snapshot();
mPackages.putAll(r.mPackages); 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 // The following assignments satisfy Java requirements but are not
// needed by the read-only methods. Note especially that the lock // 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; mDomainVerificationManager = r.mDomainVerificationManager;
mInstallerPackages.addAll(r.mInstallerPackages); mDisabledSysPackages.snapshot(r.mDisabledSysPackages);
mKernelMapping.putAll(r.mKernelMapping);
mDisabledSysPackages.putAll(r.mDisabledSysPackages);
mBlockUninstallPackages.snapshot(r.mBlockUninstallPackages); mBlockUninstallPackages.snapshot(r.mBlockUninstallPackages);
mVersion.putAll(r.mVersion); mVersion.putAll(r.mVersion);
mVerifierDeviceIdentity = r.mVerifierDeviceIdentity; mVerifierDeviceIdentity = r.mVerifierDeviceIdentity;
@@ -659,23 +688,26 @@ public final class Settings implements Watchable, Snappable {
mPersistentPreferredActivities, r.mPersistentPreferredActivities); mPersistentPreferredActivities, r.mPersistentPreferredActivities);
WatchedSparseArray.snapshot( WatchedSparseArray.snapshot(
mCrossProfileIntentResolvers, r.mCrossProfileIntentResolvers); mCrossProfileIntentResolvers, r.mCrossProfileIntentResolvers);
mSharedUsers.putAll(r.mSharedUsers); mSharedUsers.snapshot(r.mSharedUsers);
mAppIds = r.mAppIds.snapshot(); mAppIds = r.mAppIds.snapshot();
mOtherAppIds = r.mOtherAppIds.snapshot(); mOtherAppIds = r.mOtherAppIds.snapshot();
mPastSignatures.addAll(r.mPastSignatures); WatchedArrayList.snapshot(
mKeySetRefs.putAll(r.mKeySetRefs); mPastSignatures, r.mPastSignatures);
WatchedArrayMap.snapshot(
mKeySetRefs, r.mKeySetRefs);
mRenamedPackages.snapshot(r.mRenamedPackages); mRenamedPackages.snapshot(r.mRenamedPackages);
mNextAppLinkGeneration.snapshot(r.mNextAppLinkGeneration); mNextAppLinkGeneration.snapshot(r.mNextAppLinkGeneration);
mDefaultBrowserApp.snapshot(r.mDefaultBrowserApp); mDefaultBrowserApp.snapshot(r.mDefaultBrowserApp);
// mReadMessages // mReadMessages
mPendingPackages.addAll(r.mPendingPackages); WatchedArrayList.snapshot(
mPendingPackages, r.mPendingPackages);
mSystemDir = null; mSystemDir = null;
// mKeySetManagerService; // mKeySetManagerService;
mPermissions = r.mPermissions; mPermissions = r.mPermissions;
mPermissionDataProvider = r.mPermissionDataProvider; mPermissionDataProvider = r.mPermissionDataProvider;
// Do not register any Watchables and do not create a snapshot cache. // 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.startTag(null, "shared-user");
serializer.attribute(null, ATTR_NAME, usr.name); serializer.attribute(null, ATTR_NAME, usr.name);
serializer.attributeInt(null, "userId", usr.userId); serializer.attributeInt(null, "userId", usr.userId);
usr.signatures.writeXml(serializer, "sigs", mPastSignatures); usr.signatures.writeXml(serializer, "sigs", mPastSignatures.untrackedStorage());
serializer.endTag(null, "shared-user"); serializer.endTag(null, "shared-user");
} }
@@ -2736,11 +2768,11 @@ public final class Settings implements Watchable, Snappable {
writeUsesStaticLibLPw(serializer, pkg.usesStaticLibraries, pkg.usesStaticLibrariesVersions); writeUsesStaticLibLPw(serializer, pkg.usesStaticLibraries, pkg.usesStaticLibrariesVersions);
pkg.signatures.writeXml(serializer, "sigs", mPastSignatures); pkg.signatures.writeXml(serializer, "sigs", mPastSignatures.untrackedStorage());
if (installSource.initiatingPackageSignatures != null) { if (installSource.initiatingPackageSignatures != null) {
installSource.initiatingPackageSignatures.writeXml( installSource.initiatingPackageSignatures.writeXml(
serializer, "install-initiator-sigs", mPastSignatures); serializer, "install-initiator-sigs", mPastSignatures.untrackedStorage());
} }
writeSigningKeySetLPr(serializer, pkg.keySetData); writeSigningKeySetLPr(serializer, pkg.keySetData);
@@ -2909,7 +2941,7 @@ public final class Settings implements Watchable, Snappable {
} else if (TAG_READ_EXTERNAL_STORAGE.equals(tagName)) { } else if (TAG_READ_EXTERNAL_STORAGE.equals(tagName)) {
// No longer used. // No longer used.
} else if (tagName.equals("keyset-settings")) { } else if (tagName.equals("keyset-settings")) {
mKeySetManagerService.readKeySetsLPw(parser, mKeySetRefs); mKeySetManagerService.readKeySetsLPw(parser, mKeySetRefs.untrackedStorage());
} else if (TAG_VERSION.equals(tagName)) { } else if (TAG_VERSION.equals(tagName)) {
final String volumeUuid = XmlUtils.readStringAttribute(parser, final String volumeUuid = XmlUtils.readStringAttribute(parser,
ATTR_VOLUME_UUID); ATTR_VOLUME_UUID);
@@ -3697,7 +3729,7 @@ public final class Settings implements Watchable, Snappable {
} else if (tagName.equals(TAG_ENABLED_COMPONENTS)) { } else if (tagName.equals(TAG_ENABLED_COMPONENTS)) {
readEnabledComponentsLPw(packageSetting, parser, 0); readEnabledComponentsLPw(packageSetting, parser, 0);
} else if (tagName.equals("sigs")) { } else if (tagName.equals("sigs")) {
packageSetting.signatures.readXml(parser, mPastSignatures); packageSetting.signatures.readXml(parser, mPastSignatures.untrackedStorage());
} else if (tagName.equals(TAG_PERMISSIONS)) { } else if (tagName.equals(TAG_PERMISSIONS)) {
readInstallPermissionsLPr(parser, readInstallPermissionsLPr(parser,
packageSetting.getLegacyPermissionState(), users); packageSetting.getLegacyPermissionState(), users);
@@ -3728,7 +3760,7 @@ public final class Settings implements Watchable, Snappable {
packageSetting.keySetData.addDefinedKeySet(id, alias); packageSetting.keySetData.addDefinedKeySet(id, alias);
} else if (tagName.equals("install-initiator-sigs")) { } else if (tagName.equals("install-initiator-sigs")) {
final PackageSignatures signatures = new PackageSignatures(); final PackageSignatures signatures = new PackageSignatures();
signatures.readXml(parser, mPastSignatures); signatures.readXml(parser, mPastSignatures.untrackedStorage());
packageSetting.installSource = packageSetting.installSource =
packageSetting.installSource.setInitiatingPackageSignatures(signatures); packageSetting.installSource.setInitiatingPackageSignatures(signatures);
} else if (tagName.equals(TAG_DOMAIN_VERIFICATION)) { } else if (tagName.equals(TAG_DOMAIN_VERIFICATION)) {
@@ -3923,7 +3955,7 @@ public final class Settings implements Watchable, Snappable {
String tagName = parser.getName(); String tagName = parser.getName();
if (tagName.equals("sigs")) { if (tagName.equals("sigs")) {
su.signatures.readXml(parser, mPastSignatures); su.signatures.readXml(parser, mPastSignatures.untrackedStorage());
} else if (tagName.equals("perms")) { } else if (tagName.equals("perms")) {
readInstallPermissionsLPr(parser, su.getLegacyPermissionState(), users); readInstallPermissionsLPr(parser, su.getLegacyPermissionState(), users);
} else { } else {

View File

@@ -23,6 +23,7 @@ import android.os.Message;
import android.os.SystemClock; import android.os.SystemClock;
import android.text.TextUtils; import android.text.TextUtils;
import com.android.internal.annotations.GuardedBy;
import com.android.server.EventLogTags; import com.android.server.EventLogTags;
import java.io.PrintWriter; import java.io.PrintWriter;
@@ -238,6 +239,11 @@ public class SnapshotStatistics {
*/ */
public int mTotalUsed = 0; 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 * The total number of builds that count as big, which means they took longer than
* SNAPSHOT_BIG_BUILD_TIME_NS. * SNAPSHOT_BIG_BUILD_TIME_NS.
@@ -291,6 +297,13 @@ public class SnapshotStatistics {
} }
} }
/**
* Record a cork.
*/
private void corked() {
mTotalCorked++;
}
private Stats(long now) { private Stats(long now) {
mStartTimeUs = now; mStartTimeUs = now;
mTimes = new int[mTimeBins.count()]; mTimes = new int[mTimeBins.count()];
@@ -308,6 +321,7 @@ public class SnapshotStatistics {
mUsed = Arrays.copyOf(orig.mUsed, orig.mUsed.length); mUsed = Arrays.copyOf(orig.mUsed, orig.mUsed.length);
mTotalBuilds = orig.mTotalBuilds; mTotalBuilds = orig.mTotalBuilds;
mTotalUsed = orig.mTotalUsed; mTotalUsed = orig.mTotalUsed;
mTotalCorked = orig.mTotalCorked;
mBigBuilds = orig.mBigBuilds; mBigBuilds = orig.mBigBuilds;
mShortLived = orig.mShortLived; mShortLived = orig.mShortLived;
mTotalTimeUs = orig.mTotalTimeUs; mTotalTimeUs = orig.mTotalTimeUs;
@@ -365,6 +379,7 @@ public class SnapshotStatistics {
* Dump the summary statistics record. Choose the header or the data. * Dump the summary statistics record. Choose the header or the data.
* number of builds * number of builds
* number of uses * number of uses
* number of corks
* number of big builds * number of big builds
* number of short lifetimes * number of short lifetimes
* cumulative build time, in seconds * cumulative build time, in seconds
@@ -373,13 +388,13 @@ public class SnapshotStatistics {
private void dumpStats(PrintWriter pw, String indent, long now, boolean header) { private void dumpStats(PrintWriter pw, String indent, long now, boolean header) {
dumpPrefix(pw, indent, now, header, "Summary stats"); dumpPrefix(pw, indent, now, header, "Summary stats");
if (header) { if (header) {
pw.format(Locale.US, " %10s %10s %10s %10s %10s %10s", pw.format(Locale.US, " %10s %10s %10s %10s %10s %10s %10s",
"TotBlds", "TotUsed", "BigBlds", "ShortLvd", "TotBlds", "TotUsed", "TotCork", "BigBlds", "ShortLvd",
"TotTime", "MaxTime"); "TotTime", "MaxTime");
} else { } else {
pw.format(Locale.US, pw.format(Locale.US,
" %10d %10d %10d %10d %10d %10d", " %10d %10d %10d %10d %10d %10d %10d",
mTotalBuilds, mTotalUsed, mBigBuilds, mShortLived, mTotalBuilds, mTotalUsed, mTotalCorked, mBigBuilds, mShortLived,
mTotalTimeUs / 1000, mMaxBuildTimeUs / 1000); mTotalTimeUs / 1000, mMaxBuildTimeUs / 1000);
} }
pw.println(); pw.println();
@@ -516,7 +531,7 @@ public class SnapshotStatistics {
* @param done The time at which the snapshot rebuild completed, in ns. * @param done The time at which the snapshot rebuild completed, in ns.
* @param hits The number of times the previous snapshot was used. * @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 // The duration has a span of about 2000s
final int duration = (int) (done - now); final int duration = (int) (done - now);
boolean reportEvent = false; 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 * 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. * index zero. The old element zero is completed with the specified time.
*/ */
@GuardedBy("mLock")
private void shift(Stats[] s, long now) { private void shift(Stats[] s, long now) {
s[0].complete(now); s[0].complete(now);
for (int i = s.length - 1; i > 0; i--) { 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 * Dump the statistics. The format is compatible with the PackageManager dumpsys
* output. * 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. // Grab the raw statistics under lock, but print them outside of the lock.
Stats[] l; Stats[] l;
Stats[] s; Stats[] s;
@@ -608,7 +635,8 @@ public class SnapshotStatistics {
s = Arrays.copyOf(mShort, mShort.length); s = Arrays.copyOf(mShort, mShort.length);
s[0] = new Stats(s[0]); 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(); pw.println();
dump(pw, indent, now, l, s, "stats"); dump(pw, indent, now, l, s, "stats");
if (!full) { if (!full) {

View File

@@ -19,6 +19,9 @@ package com.android.server.utils;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; 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 * 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 * {@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; 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() // The source object from which snapshots are created. This may be null if createSnapshot()
// does not require it. // does not require it.
protected final T mSource; protected final T mSource;
// The cached snapshot // The cached snapshot
private T mSnapshot = null; private volatile T mSnapshot = null;
// True if the snapshot is sealed and may not be modified. // 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 * 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 source Source data for rebuilding snapshots.
* @param watchable The object that notifies when the cache is invalid. * @param watchable The object that notifies when the cache is invalid.
*/ */
public SnapshotCache(@Nullable T source, @NonNull Watchable watchable) { public SnapshotCache(@Nullable T source, @NonNull Watchable watchable) {
mSource = source; this(source, watchable, null);
watchable.registerObserver(this);
} }
/** /**
@@ -63,13 +106,14 @@ public abstract class SnapshotCache<T> extends Watcher{
public SnapshotCache() { public SnapshotCache() {
mSource = null; mSource = null;
mSealed = true; mSealed = true;
mStatistics = null;
} }
/** /**
* Notify the object that the source object has changed. If the local object is sealed then * Notify the object that the source object has changed. If the local object is sealed then
* IllegalStateException is thrown. Otherwise, the cache is cleared. * IllegalStateException is thrown. Otherwise, the cache is cleared.
*/ */
public void onChange(@Nullable Watchable what) { public final void onChange(@Nullable Watchable what) {
if (mSealed) { if (mSealed) {
throw new IllegalStateException("attempt to change a sealed object"); 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. * Seal the cache. Attempts to modify the cache will generate an exception.
*/ */
public void seal() { public final void seal() {
mSealed = true; mSealed = true;
} }
@@ -88,11 +132,14 @@ public abstract class SnapshotCache<T> extends Watcher{
* new snapshot and saves it in the cache. * new snapshot and saves it in the cache.
* @return A snapshot as returned by createSnapshot() and possibly cached. * @return A snapshot as returned by createSnapshot() and possibly cached.
*/ */
public T snapshot() { public final T snapshot() {
T s = mSnapshot; T s = mSnapshot;
if (s == null || !ENABLED) { if (s == null || !ENABLED) {
s = createSnapshot(); s = createSnapshot();
mSnapshot = s; mSnapshot = s;
if (mStatistics != null) mStatistics.mRebuilt.incrementAndGet();
} else {
if (mStatistics != null) mStatistics.mReused.incrementAndGet();
} }
return s; return s;
} }
@@ -123,4 +170,25 @@ public abstract class SnapshotCache<T> extends Watcher{
throw new UnsupportedOperationException("cannot snapshot a sealed snaphot"); 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 android.util.LongSparseArray;
import com.android.internal.util.ArrayUtils; import com.android.internal.util.ArrayUtils;
import com.android.server.utils.WatchedArrayMap;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@@ -33,7 +34,7 @@ import java.security.cert.CertificateException;
public class KeySetManagerServiceTest extends AndroidTestCase { public class KeySetManagerServiceTest extends AndroidTestCase {
private ArrayMap<String, PackageSetting> mPackagesMap; private WatchedArrayMap<String, PackageSetting> mPackagesMap;
private KeySetManagerService mKsms; private KeySetManagerService mKsms;
public PackageSetting generateFakePackageSetting(String name) { public PackageSetting generateFakePackageSetting(String name) {
@@ -46,7 +47,7 @@ public class KeySetManagerServiceTest extends AndroidTestCase {
@Override @Override
public void setUp() throws Exception { public void setUp() throws Exception {
super.setUp(); super.setUp();
mPackagesMap = new ArrayMap<String, PackageSetting>(); mPackagesMap = new WatchedArrayMap<String, PackageSetting>();
mKsms = new KeySetManagerService(mPackagesMap); mKsms = new KeySetManagerService(mPackagesMap);
} }
@@ -94,7 +95,8 @@ public class KeySetManagerServiceTest extends AndroidTestCase {
} }
public void testEncodePublicKey() throws IOException { 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); KeySetManagerService ksms = new KeySetManagerService(packagesMap);
PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA); PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);

View File

@@ -47,7 +47,6 @@ import android.os.BaseBundle;
import android.os.PersistableBundle; import android.os.PersistableBundle;
import android.os.Process; import android.os.Process;
import android.os.UserHandle; import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet; import android.util.ArraySet;
import android.util.AtomicFile; import android.util.AtomicFile;
import android.util.Log; 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.permission.LegacyPermissionDataProvider;
import com.android.server.pm.verify.domain.DomainVerificationManagerInternal; import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
import com.android.server.utils.WatchableTester; import com.android.server.utils.WatchableTester;
import com.android.server.utils.WatchedArrayMap;
import com.google.common.truth.Truth; import com.google.common.truth.Truth;
@@ -1202,9 +1202,8 @@ public class PackageManagerSettingsTests {
private void verifyKeySetMetaData(Settings settings) private void verifyKeySetMetaData(Settings settings)
throws ReflectiveOperationException, IllegalAccessException { throws ReflectiveOperationException, IllegalAccessException {
ArrayMap<String, PackageSetting> packages = WatchedArrayMap<String, PackageSetting> packages = settings.mPackages;
settings.mPackages.untrackedStorage(); KeySetManagerService ksms = settings.getKeySetManagerService();
KeySetManagerService ksms = settings.mKeySetManagerService;
/* verify keyset and public key ref counts */ /* verify keyset and public key ref counts */
assertThat(KeySetUtils.getKeySetRefCount(ksms, 1), is(2)); assertThat(KeySetUtils.getKeySetRefCount(ksms, 1), is(2));