Merge changes I8dc57930,Ia993613f,I111cc425 into sc-dev
* changes: Enable PackageManagerService snapshots Improve snapshot performance Correct snapshot races
This commit is contained in:
committed by
Android (Google) Code Review
commit
209a1ee0b1
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>>();
|
||||||
|
|||||||
@@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|||||||
Reference in New Issue
Block a user